coroutine vs function
بحثی که همیشه ذهن برنامهنویسها را درگیر میکند مبحث ناهمروندی است. و یکی از موضوعات قابل بحث کروتینها هستند. اساسا کروتینها چه تفاوتی با فانکشنها دارند؟ چرا به کروتینها نیاز پیدا میکنیم؟ چطوری کروتینها ساخته میشوند و سوالاتی از این دست.
فانکشن(تابع):
فانکشنها تسهیلاتی هستند که مانع از تکرار کد میشوند. فانکشنها یک یا چند ورودی میگیرند، عملیاتی را انجام میدهند و خروجی یا خروجیهایی را به تحویل میدهند. مثلا به تابع زیر دقت کنید:
همانطوری که میبینید تابعی به نام fun تعریف کردیم که یک ورودی به نام number میگیرد و عدد 10 را به number اضافه میکند و عدد جدید را برگشت میدهد. کدها در توابع به صورت خط به خط اجرا میشوند.
توابع چه مشکلاتی داشتند(دارند)؟
فرض کنید که در یک تابع یک فراخوانی API داشته باشیم در این صورت تابعی که در حال اجراست با وقفهای رو به رو خواهد شد. جریان اجرا در تابع فراخوانی شده است و این تابع با وقفه رو به رو شده پس کل برنامه با وقفه رو به رو خواهد شد(حتی تابع فراخوان). اینجاست که به یک مکانیزم نیاز پیدا میکنیم که توابع فراخوانی شده را اصطلاحا pause و resume کند. هر جایی که با یک وقفه ناشی از IO رو به رو شویم، تابع فراخوانی شده در همان خطی که باعث وقفه شده است pause میشود و جریان اجرا به تابع فراخوان برمیگردد وقتی که وقفه به اتمام رسید تابع دوباره resume میگردد. به چنین مکانیسمهایی coroutine میگویند. در حالتی که کروتین pause میشود یک state از آن ذخیره میشود این استیت میتواند متغیرها و دیگر موارد موجود در کروتین باشد وقتی که کروتین resume میشود حالت کروتین با استفاده از این استیت ذخیره شده بازیابی میگردد و خطوط بعد از خطی که منجر به وقفه شده است اجرا میشوند.
در تابع sync_function یک API را فراخوانی کردهام. تا وقتی که این API در حال فراخوانی است، تابع sync_function دچار وقفه شده است این در حالی است که جریان اجرا در sync_function باقی مانده و کل برنامه دچار وقفه شده است. همین کار را با استفاده از کروتینها انجام میدهیم. اولین بار با استفاده از native coroutine ها که با اضافه شدن دو کلمه کلیدی async/await به پایتون اضافه شد(برخلاف میل ون روسام) و در نهایت با استفاده از generator base coroutine های Tornado این کار را انجام خواهیم داد.
نیتیو کروتینها:
همانطور که میبینید از دو کلمه کلیدی async/await برای ایجاد این کروتین استفاده شده است. برای اجرای کروتینها باید یک event loop ایجاد کنیم . کروتین روی این لوپ اجرا خواهد شد. کد کامل به صورت زیر خواهد بود:
لوپ را ساختیم و کروتین را روی لوپ اجرا کردیم. وقتی که جریان اجرا به خط دریافت اطلاعات از API برسد، جریان اجرا به تابع فراخوان(main) برمیگردد و امکان اجرای تابع دیگری نیز وجود دارد. با اتمام دریافت اطلاعات از شبکه، جریان اجرا به fun برمیگردد. همین کار را میتوانیم با generator base coroutine های Tornado هم انجام دهیم.
در این مورد از کلمات async/await استفاده نکردیم و از coroutine به عنوان یک دکوریتور برای fun استفاده کردیم و در خط دریافت اطلاعات از شبکه با استفاده از yield جریان اجرا را به تابع فراخوان برگرداندیم. در این روش شکل کروتین بسیار شبیه به یک تابع است این مورد مربوط به قبل از اضافه شدن کلمات کلیدی async/await به پایتون بود. جامعه کاربری پایتون و در راس آنها فریمورکهای ناهمروندی مانند Tornado برای ایجاد کروتینها از سینتکس تابع استفاده میکردند و با استفاده از قابلیتها موجود در پایتون مانند decoratorها و generatorها امورات مربوط به کروتینها را انجام میدادند.
* برای ارسال درخواستها به صورت ناهمروند امکان استفاده از کتابخانه httpx نیز وجود دارد.
میخوایید تورنادو یاد بگیرید؟ جای درستی اومدید!