پاسخ تمرین ۱
وقتی تابع Blocking هیچ نقطهی await ندارد، حلقهی رویداد راهی برای سوییچ کردن به کوروتینهای دیگر ندارد، برای همین تا پایان اجرای آن تابع، کل حلقه مسدود میماند و مزیت همزمانی از بین میرود.
پاسخ تمرین ۲
run_in_executor کاری میکند که خود تابع Blocking را درون یک Thread یا Process جدا اجرا کند، در حالی که خودش یک Future برمیگرداند که میتوان منتظرش ماند. اینطوری تابع Blocking حلقهی رویداد اصلی را مسدود نمیکند.
پاسخ تمرین ۳
به دلیل اینکه run_in_executor فقط ارگومانهای موضعی را میپذیرد و از آرگومان کلیدی پشتیبانی نمیکند، باید از functools.partial استفاده کنیم تا اول آرگومانهای کلیدی را به خود تابع متصل کنیم و بعد نتیجه را به run_in_executor بدهیم.
پاسخ تمرین ۴
به دلیل GIL، Threadها نمیتوانند برای کارهای محاسباتی سنگین واقعاً موازی اجرا شوند. برای این دسته کارها باید از ProcessPoolExecutor استفاده کنیم تا کار در یک پردازش کاملاً مجزا انجام شود و واقعاً به صورت موازی اجرا شود.