اواسط ماه پیش، این رشتهتوییت از آقای Yury Selivanov منتشر شد که در داخل صحبتهاشون این جمله گفته شد:
... I believe that this makes Python one of the best-equipped languages for writing concurrent code. ...
من اعتقاد دارم که این باعث میشه پایتون یکی از مجهزترین زبانها برای نوشتن کدهای concurrent بحساب بیاد.
بریم ببینیم اون ضمیر this در این رشتو به چی اشاره داره!!
اول بیایید ببینیم ایشون چه کسی هستن؟
✔️ آقای Yury Selivanov
ایشون یکی از core developerهای پرکار پایتون هستن، که عمده فعالیتشون برای این PEPها بوده:
PEP 492
- async and await syntax
- async with
- async for
- coroutine object
PEP 525
- async generators
- async iteration protocol
PEP 530
- async comprehensions
- await in comprehensions
و مشارکت در:
PEP 654
- ExceptionGroups and except*
این هم آدرس صفحه LinkedInشون میتونید اطلاعات بیشتری راجع به ایشون اینجا پیدا کنید.
حالا که ایشون رو شناختیم و دیدیم که در دنیای async فعالیت زیادی داشتن بریم اون #رشتو رو تحلیل کنیم.
ایشون در این رشتو توضیح میدن:
چرا به TaskGroupها نیاز داشتیم؟
بعد از وقتی asyncio منتشر شد، و اون چندتا pepی که ایشون نوشتن به پایتون اضافه شد، دو تا پروژه رو دو نفر دیگه شروع کردن نوشتن، یکی Curio (توسط David Beazley) و دیگری Trio (توسط Nathaniel J. Smith).
نویسندههای این دو پروژه میخواستن با پایتون مدرن (در زمینه concurrent code، یعنی سینتکس async await و ...) یه بار دیگه یه کتابخونه شبیه به asyncio (ولی بهتر) بنویسن. وقتی که این کار رو کردن، توسعهدهندههای پایتون فهمیدن که کجاهای asyncio رو میشه بهتر کرد. برای مثال تابع
asyncio.run(...)
رو از Curio الگو برداری کردن؛ یکی دیگه از چیزهایی که بعد از سالها توسعهی EdgeDB (یکی از جدیدترین انواع دیتابیس که توسط آقای Yury selivanov و همکارش Elvis Pranskevichus نوشته شده.) و خوندن source پروژه Trio، در پایتون احساس میشد چیزی بود به اسم TaskGroupها.
قبل از اینکه توضیح بدم چرا به تسکگروپها پایتون احتیاج داشت باید بگم وقتی شما چند تا Task رو میخواید باهم await کنید، apiی که الان در اختیار شماست، تابعی هست به اسم asyncio.gather. (در واقع معرفی TaskGroupها برای جایگزین کردن اونها بجای asyncio.gather هست)
برای مثال:
این تابع میاد و این taskها رو باهم و همزمان await میکنه، و هر چیزی که ازشون برگشت داده شد جمع میکنه و برای ما return میکنه.
این تابع یک آرگومان اختیاری هم دریافت میکنه به اسم return_exception که به صورت پیشفرض False هست، اما اگر اون رو True قرار بدیم، دیگر هیچ exceptionعی raise نیمشه و آبجکتهای exceptionهای raise شده درون تسکها به ما برگشت داده میشه:
مشکلات ما چی هستن؟
یکی از مشکلاتی که این تابع داره، وقتی که در یکی از تسکها یک exception رخ میده، اون رو propagate میکنه، اما باقی تسکها به کارشون ادامه میدن و کَنسِل نمیشن و این یک مشکل هست.
مشکل دیگهای که هست وقتی که شما آرگومان return_exception رو True قرار میدید، دیگه هیچ exceptionعی raise نمیشه و فقط آبجکت اونا به ما برگشت داده میشه.
این api جالب و جذابی نیست و کارکردن باهاش یه ذره اذیت کننده و سنیگن هست و طبق ذن پایتون:
Errors should never pass silently
چه چیز(هایی) باید قبل از اینکه این مشکلات برطرف بشه به پایتون اضافه میشد؟
برای رفع مشکلات بالا باید یک مفهوم و مکانیزمی مثل multi error بوجود میومد: توسعه دهندهها واسه اینکار اومدن چیزی به عنوان ExceptionGroup هارو به پایتون اضافه کردن. با اضافه شدنشون، یک سینتکس جدید برای پایتون معرفی شد:
که با این قابلیت میشه چند تا exception رو یکجا باهم گرفت:
در try except قدیمی، حداکثر یک بلاک except میتونست اجرا بشه، اما با exception groupها یک بار raise شدن یک ExceptionGroup میتونه باعث execute شدن چندتا بلاک کد *except بشه.
الان که ExceptionGroupها رو هم داریم میتونیم که با استفاده درست ازشون به خوبی TaskGroupها رو هم داشته باشیم.
از TaskGroupها میشه بجای چه چیزی استفاده کرد؟
حالا که این هم به پایتون اضافه شد، دیگه میشه راحت از TaskGroupها استفاده کرد؛ کارکردی شبیه به gather اما بهتر و قشنگتر
فواید TaskGroupها:
تسک گروپها از پایتون ۳.۱۱ به پایتون اضافه خواهند شد.
ایشون بعد از اینهمه تجربه و کار در دنیای asyncio در پایتون در این رشتو این جمله رو گفتن:
من اعتقاد دارم که این باعث میشه پایتون یکی از مجهزترین زبانها برای نوشتن کدهای concurrent بحساب بیاد.
پایتون انواع و اقسام روشها، رویهها و ابزارها و فریمورکهای نوشتن کدهای concurrent و parallel رو در اختیار ما میگذاره؛ اینها براحتی میتونن انواع و اقسام مشکلات رو برای ما براحتی برطرف کنن، از نوشتن کدهای IO bound با asyncio و threading تا موازی سازی و اجرا کردن کدهای CPU bound همچنان با asyncio multiprocessing و subinterpreters وغیره و ذالک.
Happy Pythoning :)