همروالها و وظایف¶
این بخش، مروری بر APIهای سطح بالای asyncio برای کار با همروالها و وظیفهها ارائه میدهد.
همروالها¶
کد منبع: Lib/asyncio/coroutines.py
تعریف همروالها با سینتکس async/await، روش ترجیحی برای نوشتن برنامههای asyncio است. برای مثال، قطعهکد زیر "hello" را چاپ میکند، ۱ ثانیه منتظر میماند، و سپس "world" را چاپ میکند:
>>> import asyncio
>>> async def main():
... print('hello')
... await asyncio.sleep(1)
... print('world')
>>> asyncio.run(main())
hello
world
توجه داشته باشید که صرفاً فراخوانی یک همروال، آن را برای اجرا زمانبندی نمیکند:
>>> main()
<coroutine object main at 0x1053bb7c8>
برای اجرای واقعی یک همروال، asyncio سازوکارهای زیر را فراهم میکند:
تابع
asyncio.run()برای اجرای تابع نقطه ورود سطح بالا "main()" (مثال بالا را ببینید.)در انتظار یک همروال. قطعهکد زیر پس از انتظار برای ۱ ثانیه، «hello» را چاپ میکند و سپس «world» را پس از انتظار برای ۲ ثانیهی دیگر چاپ خواهد کرد:
import asyncio import time async def say_after(delay, what): await asyncio.sleep(delay) print(what) async def main(): print(f"started at {time.strftime('%X')}") await say_after(1, 'hello') await say_after(2, 'world') print(f"finished at {time.strftime('%X')}") asyncio.run(main())
خروجی مورد انتظار:
started at 17:13:52 hello world finished at 17:13:55
تابع
asyncio.create_task()برای اجرای همزمان همروالها بهعنوانTasksدر asyncio.بیایید مثال بالا را تغییر دهیم و دو همروال
say_afterرا همزمان اجرا کنیم:async def main(): task1 = asyncio.create_task( say_after(1, 'hello')) task2 = asyncio.create_task( say_after(2, 'world')) print(f"started at {time.strftime('%X')}") # Wait until both tasks are completed (should take # around 2 seconds.) await task1 await task2 print(f"finished at {time.strftime('%X')}")
توجه داشته باشید که خروجی مورد انتظار اکنون نشان میدهد که قطعهکد ۱ ثانیه سریعتر از قبل اجرا میشود:
started at 17:14:32 hello world finished at 17:14:34
کلاس
asyncio.TaskGroupجایگزین مدرنتری برایcreate_task()فراهم میکند. با استفاده از این API، آخرین مثال بهشکل زیر درمیآید:async def main(): async with asyncio.TaskGroup() as tg: task1 = tg.create_task( say_after(1, 'hello')) task2 = tg.create_task( say_after(2, 'world')) print(f"started at {time.strftime('%X')}") # The await is implicit when the context manager exits. print(f"finished at {time.strftime('%X')}")
زمانبندی و خروجی باید مانند نسخهی پیشین یکسان باشند.
اضافه شده در نسخهی 3.11:
asyncio.TaskGroup.
Awaitableها¶
میگوییم که یک شیء در صورتی یک شیء awaitable است که بتوان از آن در یک عبارت await استفاده کرد. بسیاری از APIهای asyncio برای پذیرش awaitableها طراحی شدهاند.
سه نوع اصلی از اشیای awaitable وجود دارد: همروالها، Taskها و Futureها.
همروالها
همروالهای پایتون awaitables هستند و بنابراین میتوان آنها را از همروالهای دیگر await کرد:
import asyncio
async def nested():
return 42
async def main():
# Nothing happens if we just call "nested()".
# A coroutine object is created but not awaited,
# so it *won't run at all*.
nested() # will raise a "RuntimeWarning".
# Let's do it differently now and await it:
print(await nested()) # will print "42".
asyncio.run(main())
مهم
در این مستندات، اصطلاح «همروال» میتواند برای دو مفهوم بسیار مرتبط بهکار رود:
یک تابع همروال: یک تابع
async def؛یک شیء همروال: شیءای که با فراخوانی یک تابع همروال برگردانده میشود.
وظایف
وظایف برای زمانبندی همروالها بهصورت همزمان استفاده میشوند.
هنگامی که یک همروال با توابعی مانند asyncio.create_task() در یک Task قرار میگیرد، آن همروال بهطور خودکار زمانبندی میشود تا بهزودی اجرا شود:
import asyncio
async def nested():
return 42
async def main():
# Schedule nested() to run soon concurrently
# with "main()".
task = asyncio.create_task(nested())
# "task" can now be used to cancel "nested()", or
# can simply be awaited to wait until it is complete:
await task
asyncio.run(main())
آیندهنماها (Futures)
Future یک شیء خاص سطح پایین قابل await (awaitable) است که نشاندهندهی نتیجه نهایی یک عملیات ناهمگام است.
هنگامی که یک شیء Future await میشود، به این معنا است که همروال منتظر میماند تا Future در جای دیگری حل شود.
اشیای Future در asyncio لازم هستند تا بتوان از کد مبتنی بر کالبک با async/await استفاده کرد.
معمولاً نیازی نیست که اشیای Future را در کد سطح برنامه ایجاد کنید.
اشیای Future را، که گاهی از طریق کتابخانهها و برخی APIهای asyncio در دسترس قرار میگیرند، میتوان await کرد:
async def main():
await function_that_returns_a_future_object()
# this is also valid:
await asyncio.gather(
function_that_returns_a_future_object(),
some_python_coroutine()
)
یک نمونه خوب از یک تابع سطح پایین که یک شیء Future را بازمیگرداند، loop.run_in_executor() است.
ایجاد وظایف¶
کد منبع: Lib/asyncio/tasks.py
- asyncio.create_task(coro, *, name=None, context=None, eager_start=None, **kwargs)¶
همروال coro را در یک
Taskقرار میدهد و اجرای آن را زمانبندی میکند. شیء Task را برمیگرداند.امضای کامل تابع تا حد زیادی مشابه سازندهی
Task(یا کارخانه) است؛ تمام آرگومانهای کلیدواژهای این تابع به آن رابط منتقل میشوند.یک آرگومان اختیاری فقط کلیدواژهای context به شما امکان میدهد یک
contextvars.Contextسفارشی برای اجرای coro مشخص کنید. اگر context ارائه نشود، یک کپی از زمینه فعلی ایجاد میشود.یک آرگومان اختیاری فقط کلیدواژهای eager_start به شما امکان میدهد مشخص کنید که آیا وظیفهباید در حین فراخوانی create_task بهصورت فوری اجرا شود یا بعداً زمانبندی شود. اگر eager_start ارسال نشود، حالت تنظیمشده توسط
loop.set_task_factory()استفاده خواهد شد.این وظیفه در حلقهای که
get_running_loop()برمیگرداند اجرا میشود؛ اگر حلقهی در حال اجرا در نخ جاری وجود نداشته باشد،RuntimeErrorپرتاب میشود.توجه
asyncio.TaskGroup.create_task()جایگزینی جدید است که از همروندی ساختاری بهره میگیرد؛ این امکان را فراهم میکند که با تضمینهای نیرومند ایمنی، منتظر گروهی از وظایف مرتبط بمانید.مهم
برای جلوگیری از ناپدید شدن یک وظیفه در میانهی اجرا، یک ارجاع به نتیجهی این تابع ذخیره کنید. حلقهی رویداد تنها ارجاعهای ضعیف به وظایف را نگه میدارد. وظیفهای که در جای دیگری به آن ارجاع داده نشده است، ممکن است در هر زمانی زبالهروبی شود، حتی پیش از آنکه به پایان برسد. برای وظایف پسزمینهی قابلاطمینان از نوع «fire-and-forget»، آنها را در یک مجموعه گردآوری کنید:
background_tasks = set() for i in range(10): task = asyncio.create_task(some_coro(param=i)) # Add task to the set. This creates a strong reference. background_tasks.add(task) # To prevent keeping references to finished tasks forever, # make each task remove its own reference from the set after # completion: task.add_done_callback(background_tasks.discard)
Note that this approach never awaits the tasks, so if a task fails, its exception is never retrieved and asyncio logs a "Task exception was never retrieved" message when the task is garbage collected. To avoid this, use
asyncio.TaskGroupwhich keeps a strong reference to each task, awaits them and propagates their exceptions:async with asyncio.TaskGroup() as tg: for i in range(10): tg.create_task(some_coro(param=i))
اضافه شده در نسخهی 3.7.
تغییر یافته در نسخهی 3.8: پارامتر name افزوده شد.
تغییر یافته در نسخهی 3.11: پارامتر context افزوده شد.
تغییر یافته در نسخهی 3.14: پارامتر eager_start با ارسال تمام kwargs افزوده شد.
لغو وظیفه¶
وظایف را میتوان بهآسانی و بهصورت امن لغو کرد. هنگامی که یک وظیفه لغو میشود، asyncio.CancelledError در اولین فرصت در آن وظیفه پرتاب خواهد شد.
توصیه میشود همروالها از بلوکهای try/finally برای انجام منطق پاکسازی بهصورت مقاوم استفاده کنند. در صورتی که asyncio.CancelledError بهطور صریح گرفته شود، معمولاً باید پس از تکمیل پاکسازی انتشار یابد. asyncio.CancelledError مستقیماً زیرکلاس BaseException است، بنابراین بیشتر کدها نیازی به آگاهی از آن نخواهند داشت.
کامپوننتهای asyncio که همروندی ساختاریافته را فراهم میکنند، مانند asyncio.TaskGroup و asyncio.timeout()، بهصورت داخلی با استفاده از لغو پیادهسازی شدهاند و ممکن است در صورتی که یک همروال asyncio.CancelledError را نادیده بگیرد، رفتار نادرستی داشته باشند. بهطور مشابه، کد کاربر عموماً نباید uncancel را فراخوانی کند. با این حال، در مواردی که سرکوب asyncio.CancelledError واقعاً مطلوب باشد، لازم است uncancel() نیز فراخوانی شود تا وضعیت لغو بهطور کامل حذف شود.
گروههای وظیفه (Task groups)¶
گروههای وظیفه، یک API برای ایجاد وظیفه را با روشی راحت و مطمئن برای منتظر ماندن تا پایانیافتن تمام وظایف گروه ترکیب میکنند.
- class asyncio.TaskGroup¶
یک مدیر زمینه ناهمگام که گروهی از وظایف را نگه میدارد. میتوان وظایف را با استفاده از
create_task()به گروه اضافه کرد. هنگام خروج مدیر زمینه، همه وظایف await میشوند.اضافه شده در نسخهی 3.11.
- create_task(coro, *, name=None, context=None, eager_start=None, **kwargs)¶
Create a task in this task group. The signature matches that of
asyncio.create_task(). If the task group is inactive (e.g. not yet entered, already finished, or in the process of shutting down), we will close the givencoroand raiseRuntimeError.تغییر یافته در نسخهی 3.13: اگر گروه وظیفه فعال نیست، همروال دادهشده را ببندید.
تغییر یافته در نسخهی 3.14: تمام kwargs را به
loop.create_task()منتقل میکند
مثال:
async def main():
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(some_coro(...))
task2 = tg.create_task(another_coro(...))
print(f"Both tasks have completed now: {task1.result()}, {task2.result()}")
دستور async with منتظر میماند تا تمام وظایف گروه به پایان برسند. در حین انتظار، همچنان ممکن است وظایف جدیدی به گروه اضافه شوند (برای مثال، با پاس دادن tg به یکی از همروالها و فراخوانی tg.create_task() در آن همروال). پس از پایان آخرین وظیفه و خروج از بلوک async with، دیگر نمیتوان وظیفه جدیدی به گروه اضافه کرد.
اولین باری که هر وظیفهیمتعلق به گروه با استثنایی غیر از asyncio.CancelledError شکست بخورد، وظایف باقیمانده در گروه لغو میشوند. پس از آن، دیگر نمیتوان وظیفه دیگری به گروه افزود. در این نقطه، اگر بدنه دستور async with هنوز فعال باشد (یعنی __aexit__() هنوز فراخوانی نشده باشد)، وظیفهی که مستقیماً دربرگیرنده دستور async with است نیز لغو میشود. asyncio.CancelledError حاصل، یک await را قطع میکند، اما از دستور async with دربرگیرنده بیرون نخواهد زد.
پس از پایان یافتن همه وظایف، اگر هر یک از وظایف با استثنایی غیر از asyncio.CancelledError شکست خورده باشند، آن استثناها در یک ExceptionGroup یا BaseExceptionGroup (بسته به مورد؛ مستندات آنها را ببینید) ترکیب میشوند که سپس پرتاب میشود.
دو استثنای پایه بهصورت ویژه مدیریت میشوند: اگر هر وظیفهای با KeyboardInterrupt یا SystemExit شکست بخورد، گروه وظیفه (task group) همچنان وظایف باقیمانده را لغو میکند و منتظر آنها میماند، اما سپس KeyboardInterrupt یا SystemExit اولیه بهجای ExceptionGroup یا BaseExceptionGroup دوباره پرتاب میشود.
اگر بدنهی دستور async with با یک استثنا خارج شود (بنابراین __aexit__() در حالی فراخوانی میشود که یک استثنا تنظیم شده است)، با این مورد مانند حالتی رفتار میشود که یکی از وظایف شکست خورده باشد: وظایف باقیمانده لغو میشوند و سپس برای آنها انتظار میرود، و استثناهای غیر از لغو در یک گروه استثنا دستهبندی و پرتاب میشوند. استثنایی که به __aexit__() داده میشود، مگر آنکه asyncio.CancelledError باشد، نیز در گروه استثنا گنجانده میشود. همان حالت خاص پاراگراف قبلی برای KeyboardInterrupt و SystemExit نیز اعمال میشود.
گروههای وظیفه مراقب هستند که لغو داخلیِ استفادهشده برای «بیدار کردن» __aexit__() خود را با درخواستهای لغو برای وظیفهی که در آن در حال اجرا هستند و از سوی طرفهای دیگر مطرح شدهاند، اشتباه نگیرند. بهویژه، هنگامی که یک گروه وظیفه از نظر نحوی در گروه دیگری تودرتو شده باشد و هر دو همزمان در یکی از وظایف فرزند خود با استثنا مواجه شوند، گروه وظیفه داخلی استثناهای خود را پردازش میکند و سپس گروه وظیفه خارجی لغو دیگری را دریافت میکند و استثناهای خود را پردازش میکند.
در حالتی که یک گروه وظیفه از بیرون لغو میشود و همچنین باید یک ExceptionGroup را پرتاب کند، متد cancel() مربوط به وظیفهی والد (parent task) را فراخوانی میکند. این کار تضمین میکند که یک asyncio.CancelledError در await بعدی پرتاب میشود، بنابراین لغو از دست نمیرود.
گروههای Task تعداد لغو گزارششده توسط asyncio.Task.cancelling() را حفظ میکنند.
تغییر یافته در نسخهی 3.13: مدیریت بهتر لغوهای همزمان داخلی و خارجی و حفظ صحیح تعداد لغوها.
پایان دادن به گروه وظیفه¶
اگرچه پایان دادن به یک گروه وظیفه بهصورت بومی توسط کتابخانه استاندارد پشتیبانی نمیشود، میتوان با افزودن وظیفهای که استثنا پرتاب میکند به گروه وظیفه و نادیده گرفتن استثنای پرتابشده، آن را پایان داد:
import asyncio
from asyncio import TaskGroup
class TerminateTaskGroup(Exception):
"""Exception raised to terminate a task group."""
async def force_terminate_task_group():
"""Used to force termination of a task group."""
raise TerminateTaskGroup()
async def job(task_id, sleep_time):
print(f'Task {task_id}: start')
await asyncio.sleep(sleep_time)
print(f'Task {task_id}: done')
async def main():
try:
async with TaskGroup() as group:
# spawn some tasks
group.create_task(job(1, 0.5))
group.create_task(job(2, 1.5))
# sleep for 1 second
await asyncio.sleep(1)
# add an exception-raising task to force the group to terminate
group.create_task(force_terminate_task_group())
except* TerminateTaskGroup:
pass
asyncio.run(main())
خروجی مورد انتظار:
Task 1: start
Task 2: start
Task 1: done
توقف¶
- async asyncio.sleep(delay, result=None)¶
به مدت delay ثانیه مسدود میشود.
اگر result ارائه شده باشد، پس از تکمیل همروال، به فراخواننده بازگردانده میشود.
sleep()همیشه وظیفهجاری را معلق میکند و به سایر وظایف اجازه اجرا میدهد.تنظیم تأخیر روی ۰ مسیر بهینهای را فراهم میکند که به سایر وظایف اجازه اجرا میدهد. توابع طولانیمدت میتوانند از این امکان برای جلوگیری از مسدود کردن حلقه رویداد در تمام مدت فراخوانی تابع استفاده کنند.
مثالی از یک همروال که تاریخ جاری را هر ثانیه به مدت ۵ ثانیه نمایش میدهد:
import asyncio import datetime as dt async def display_date(): loop = asyncio.get_running_loop() end_time = loop.time() + 5.0 while True: print(dt.datetime.now()) if (loop.time() + 1.0) >= end_time: break await asyncio.sleep(1) asyncio.run(display_date())
تغییر یافته در نسخهی 3.10: پارامتر loop حذف شد.
تغییر یافته در نسخهی 3.13: اگر delay برابر با
nanباشد،ValueErrorپرتاب میشود.
اجرای همزمان وظایف¶
- awaitable asyncio.gather(*aws, return_exceptions=False)¶
اشیاء awaitable را در دنبالهی aws بهصورت همزمان اجرا کنید.
اگر هر awaitable در aws یک همروال باشد، بهطور خودکار بهعنوان یک Task زمانبندی میشود.
اگر همهی awaitableها با موفقیت کامل شوند، نتیجه یک فهرست تجمیعی از مقادیر بازگشتی است. ترتیب مقادیر نتیجه با ترتیب awaitableها در aws مطابقت دارد.
اگر return_exceptions
False(پیشفرض) باشد، نخستین استثنای پرتابشده بلافاصله به وظیفهای کهgather()را await میکند، منتشر میشود. سایر اشیاء قابل انتظار (awaitable) در دنبالهی aws لغو نخواهند شد و به اجرا ادامه خواهند داد.اگر return_exceptions برابر
Trueباشد، استثناها همانند نتایج موفق در نظر گرفته میشوند و در فهرست نتایج جمعآوری میشوند.اگر
gather()لغو شود، تمام awaitableهای ارسالشده (که هنوز کامل نشدهاند) نیز لغو میشوند.اگر هر Task یا Future از دنبالهی aws لغوشده باشد، با آن بهگونهای رفتار میشود که گویی
CancelledErrorرا پرتاب کرده است — در این حالت، فراخوانیgather()لغو نمیشود. این برای جلوگیری از این است که لغو یک Task/Future ارسالشده، باعث لغو سایر Taskها/Futureها شود.توجه
یک جایگزین جدید برای ایجاد و اجرای همزمان وظیفهها و انتظار برای تکمیل آنها،
asyncio.TaskGroupاست. TaskGroup برای زمانبندی زیروظیفههای تودرتو، نسبت به gather تضمینهای ایمنی قویتری فراهم میکند: اگر یک وظیفه (یا یک زیروظیفه، یعنی وظیفهای که توسط یک وظیفه زمانبندی شده است) استثنایی را پرتاب کند، TaskGroup وظیفههای زمانبندیشدهی باقیمانده را لغو میکند، در حالی که gather این کار را نمیکند.مثال:
import asyncio async def factorial(name, number): f = 1 for i in range(2, number + 1): print(f"Task {name}: Compute factorial({number}), currently i={i}...") await asyncio.sleep(1) f *= i print(f"Task {name}: factorial({number}) = {f}") return f async def main(): # Schedule three calls *concurrently*: L = await asyncio.gather( factorial("A", 2), factorial("B", 3), factorial("C", 4), ) print(L) asyncio.run(main()) # Expected output: # # Task A: Compute factorial(2), currently i=2... # Task B: Compute factorial(3), currently i=2... # Task C: Compute factorial(4), currently i=2... # Task A: factorial(2) = 2 # Task B: Compute factorial(3), currently i=3... # Task C: Compute factorial(4), currently i=3... # Task B: factorial(3) = 6 # Task C: Compute factorial(4), currently i=4... # Task C: factorial(4) = 24 # [2, 6, 24]
توجه
اگر return_exceptions نادرست باشد، لغو gather() پس از آنکه بهعنوان انجامشده علامتگذاری شده باشد، هیچکدام از موارد قابل await (awaitable) ارسالشده را لغو نمیکند. برای مثال، gather میتواند پس از انتشار یک استثنا به فراخواننده، بهعنوان انجامشده علامتگذاری شود؛ بنابراین، فراخوانی
gather.cancel()پس از گرفتن استثنایی از gather (که توسط یکی از موارد قابل await پرتابشده است)، هیچ مورد قابل await دیگری را لغو نمیکند.تغییر یافته در نسخهی 3.7: اگر خود gather لغو شود، لغو صرفنظر از return_exceptions انتشار مییابد.
تغییر یافته در نسخهی 3.10: پارامتر loop حذف شد.
منسوخ شده از نسخهی 3.10: در صورتی که هیچ آرگومان جایگاهی ارائه نشده باشد یا همهی آرگومانهای جایگاهی اشیای Future-مانند نباشند و هیچ حلقهی رویدادی در حال اجرا وجود نداشته باشد، هشدار از رده خارج شدن نشان داده میشود.
کارخانهی وظیفه حریصانه (Eager task factory)¶
- asyncio.eager_task_factory(loop, coro, *, name=None, context=None)¶
یک کارخانهی وظیفهبرای اجرای فوری وظیفه.
هنگام استفاده از این کارخانه (از طریق
loop.set_task_factory(asyncio.eager_task_factory))، همروالها اجرای خود را بهصورت همگام در حین ساختTaskآغاز میکنند. وظایفتنها در صورتی که مسدود شوند، در حلقه رویداد زمانبندی میشوند. این میتواند بهبودی در عملکرد باشد، زیرا از سربار زمانبندی حلقه برای همروالهایی که بهصورت همگام کامل میشوند جلوگیری میشود.یک مثال رایج که در آن این موضوع مفید است، همروالهایی هستند که از نهانگاهسازی یا بهخاطرسپاری (memoization) برای پرهیز از ورودی/خروجی واقعی در صورت امکان استفاده میکنند.
توجه
اجرای فوری همروال یک تغییر معنایی است. اگر همروال مقداری برگرداند یا استثنایی پرتاب کند، وظیفه هرگز در حلقه رویداد زمانبندی نمیشود. اگر اجرای همروال مسدود شود، وظیفه در حلقه رویداد زمانبندی میشود. این تغییر ممکن است تغییراتی در رفتار برنامههای موجود ایجاد کند. برای مثال، ترتیب اجرای وظایف برنامه احتمالاً تغییر خواهد کرد.
اضافه شده در نسخهی 3.12.
- asyncio.create_eager_task_factory(custom_task_constructor)¶
یک کارخانه وظیفه فوری ایجاد کنید، مشابه
eager_task_factory()، که هنگام ایجاد یک وظیفه جدید، بهجایTaskپیشفرض، از custom_task_constructor ارائهشده استفاده میکند.custom_task_constructor باید یک فراخوانیپذیر با امضایی مطابق با امضای
Task.__init__باشد. این فراخوانیپذیر باید یک شیء سازگار باasyncio.Taskبازگشت دهد.این تابع یک شیء فراخوانیپذیر را برمیگرداند که برای استفاده بهعنوان کارخانهی وظیفه یک حلقهی رویداد از طریق
loop.set_task_factory(factory)در نظر گرفته شده است.اضافه شده در نسخهی 3.12.
محافظت در برابر لغو¶
- awaitable asyncio.shield(aw)¶
از یک شیء awaitable در برابر
لغو شدنمحافظت کنید.اگر aw یک همروال باشد، بهطور خودکار بهعنوان یک Task زمانبندی میشود.
دستور:
task = asyncio.create_task(something()) res = await shield(task)
معادل است با:
res = await something()
به جز اینکه اگر همروال حاوی آن لغو شود، Task در حال اجرا در
something()لغو نمیشود. از دیدsomething()، لغو رخ نداده است. اگرچه فراخوانندهی آن همچنان لغو میشود، بنابراین عبارت "await" همچنان یکCancelledErrorرا پرتاب میکند.اگر
something()به روشهای دیگر لغو شود (یعنی از درون خودش)، این موضوعshield()را نیز لغو میکند.اگر مطلوب باشد که لغو (cancellation) بهطور کامل نادیده گرفته شود (توصیه نمیشود)، باید تابع
shield()را با یک بند try/except ترکیب کرد، بهصورت زیر:task = asyncio.create_task(something()) try: res = await shield(task) except CancelledError: res = None
مهم
برای جلوگیری از ناپدید شدن یک وظیفه در میانهی اجرا، ارجاعی به وظایف دادهشده به این تابع ذخیره کنید. حلقهی رویداد فقط ارجاعهای ضعیف به وظایف را نگه میدارد. وظیفهی که در جای دیگری به آن ارجاع داده نشده است، ممکن است در هر زمانی، حتی پیش از آنکه به پایان برسد، زبالهروبی شود.
تغییر یافته در نسخهی 3.10: پارامتر loop حذف شد.
منسوخ شده از نسخهی 3.10: اگر aw یک شیء شبیه Future نباشد و حلقه رویدادی در حال اجرا وجود نداشته باشد، هشدار از رده خارج شدن نشان داده میشود.
مهلتهای زمانی¶
- asyncio.timeout(delay)¶
یک مدیر زمینه ناهمگام برمیگرداند که میتوان از آن برای محدود کردن مدت زمانی که صرف انتظار برای چیزی میشود استفاده کرد.
delay میتواند
Noneیا عددی از نوع float/int برای تعداد ثانیههای انتظار باشد. اگر delay برابرNoneباشد، هیچ محدودیت زمانی اعمال نخواهد شد؛ این موضوع میتواند زمانی مفید باشد که تأخیر در هنگام ایجاد مدیر زمینه نامشخص باشد.در هر صورت، میتوان مدیر زمینه را پس از ایجاد، با استفاده از
Timeout.reschedule()دوباره زمانبندی کرد.مثال:
async def main(): async with asyncio.timeout(10): await long_running_task()
اگر تکمیل
long_running_taskبیش از ۱۰ ثانیه طول بکشد، مدیر زمینه، وظیفه جاری را لغو میکند وasyncio.CancelledErrorحاصل را بهصورت داخلی مدیریت میکند و آن را بهTimeoutErrorتبدیل میکند که میتوان آن را گرفت و مدیریت کرد.توجه
مدیر زمینهی
asyncio.timeout()همان چیزی است کهasyncio.CancelledErrorرا بهTimeoutErrorتبدیل میکند، به این معنا کهTimeoutErrorفقط در خارج از مدیر زمینه قابل گرفتن است.نمونهای از گرفتن
TimeoutError:async def main(): try: async with asyncio.timeout(10): await long_running_task() except TimeoutError: print("The long operation timed out, but we've handled it.") print("This statement will run regardless.")
مدیر زمینه تولیدشده توسط
asyncio.timeout()میتواند برای مهلتی دیگر دوباره زمانبندی و بازرسی شود.- class asyncio.Timeout(when)¶
یک مدیر زمینه ناهمگام برای لغو همروالهای منقضیشده.
ترجیحاً بهجای نمونهسازی مستقیم
Timeout، ازasyncio.timeout()یاasyncio.timeout_at()استفاده کنید.whenباید یک زمان مطلق باشد که در آن زمینه باید منقضی شود، همانطور که با ساعت حلقه رویداد اندازهگیری میشود:اگر
whenبرابرNoneباشد، مهلت زمانی هرگز فعال نخواهد شد.اگر
when < loop.time()باشد، مهلت زمانی در تکرار بعدی حلقه رویداد فعال خواهد شد.
مثال:
async def main(): try: # We do not know the timeout when starting, so we pass ``None``. async with asyncio.timeout(None) as cm: # We know the timeout now, so we reschedule it. new_deadline = get_running_loop().time() + 10 cm.reschedule(new_deadline) await long_running_task() except TimeoutError: pass if cm.expired(): print("Looks like we haven't finished on time.")
میتوان مدیران زمینهی مهلت زمانی را با اطمینان تودرتو کرد.
اضافه شده در نسخهی 3.11.
- asyncio.timeout_at(when)¶
مشابه
asyncio.timeout()، با این تفاوت که when زمان مطلق برای توقف انتظار است، یاNone.مثال:
async def main(): loop = get_running_loop() deadline = loop.time() + 20 try: async with asyncio.timeout_at(deadline): await long_running_task() except TimeoutError: print("The long operation timed out, but we've handled it.") print("This statement will run regardless.")
اضافه شده در نسخهی 3.11.
- async asyncio.wait_for(aw, timeout)¶
منتظر بمانید تا aw awaitable با یک مهلت زمانی کامل شود.
timeout میتواند
Noneیا یک عدد float یا int بهعنوان تعداد ثانیههای انتظار باشد. اگر timeout برابرNoneباشد، تا زمانی که future تکمیل شود، مسدود میشود.If a timeout occurs, it cancels aw and raises
TimeoutError.To prevent aw from being cancelled, wrap it in
shield().این تابع تا زمانی که فیوچر (future) بهطور واقعی لغو شود، صبر میکند، بنابراین کل زمان انتظار ممکن است از timeout فراتر رود. اگر در حین لغو استثنایی رخ دهد، آن استثنا انتشار مییابد.
اگر انتظار لغو شود، آینده aw نیز لغو میشود.
مثال:
async def eternity(): # Sleep for one hour await asyncio.sleep(3600) print('yay!') async def main(): # Wait for at most 1 second try: await asyncio.wait_for(eternity(), timeout=1.0) except TimeoutError: print('timeout!') asyncio.run(main()) # Expected output: # # timeout!
تغییر یافته در نسخهی 3.7: هنگامی که aw به دلیل مهلت زمانی لغو میشود،
wait_forمنتظر میماند تا aw لغو شود. پیش از این، بلافاصلهTimeoutErrorرا پرتاب میکرد.تغییر یافته در نسخهی 3.10: پارامتر loop حذف شد.
تغییر یافته در نسخهی 3.11:
TimeoutErrorرا بهجایasyncio.TimeoutErrorپرتاب میکند.تغییر یافته در نسخهی 3.12: Implemented using
asyncio.timeout(), a coroutine passed as aw is no longer wrapped in aTaskwhen timeout is positive.
اولیههای انتظار¶
- async asyncio.wait(aws, *, timeout=None, return_when=ALL_COMPLETED)¶
نمونههای
FutureوTaskموجود در پیمایشپذیر aws را بهطور همزمان اجرا میکند و تا برقراری شرط مشخصشده توسط return_when مسدود میشود.پیمایشپذیر aws نباید خالی باشد.
دو مجموعه از Tasks/Futures را برمیگرداند:
(done, pending).استفاده:
done, pending = await asyncio.wait(aws)
timeout (یک float یا int)، در صورت مشخص بودن، میتواند برای کنترل حداکثر تعداد ثانیههای انتظار پیش از بازگشت استفاده شود.
توجه داشته باشید که این تابع
TimeoutErrorرا پرتاب نمیکند. Futureها یا Taskهایی که هنگام فرا رسیدن مهلت زمانی انجام نشدهاند، بهسادگی در مجموعه دوم برگردانده میشوند.return_when نشان میدهد که این تابع چه زمانی باید بازگشت کند. این مقدار باید یکی از ثابتهای زیر باشد:
ثابت
توضیح
- asyncio.FIRST_COMPLETED¶
تابع هنگامی بازگشت خواهد کرد که هر فیوچر به پایان برسد یا لغو شود.
- asyncio.FIRST_EXCEPTION¶
این تابع هنگامی بازگشت میکند که هر فیوچر با پرتاب یک استثنا به پایان برسد. اگر هیچ فیوچری استثنا پرتاب نکند، معادل
ALL_COMPLETEDخواهد بود.- asyncio.ALL_COMPLETED¶
تابع زمانی بازگشت میکند که همهی آیندهنماها (futures) پایان یابند یا لغو شوند.
برخلاف
wait_for()،wait()در صورت وقوع مهلت زمانی، آیندهنماها (futures) را لغو نمیکند.اگر
wait()لغو شود، آیندهنماها (futures) موجود در aws لغو نمیشوند و به اجرای خود ادامه میدهند.تغییر یافته در نسخهی 3.10: پارامتر loop حذف شد.
تغییر یافته در نسخهی 3.11: ارسال اشیای همروال به
wait()بهصورت مستقیم ممنوع است.تغییر یافته در نسخهی 3.12: پشتیبانی از تولیدگرهایی که وظایف را yield میکنند، افزوده شد.
- asyncio.as_completed(aws, *, timeout=None)¶
اشیاء awaitable موجود در پیمایشپذیر aws را بهصورت همزمان اجرا کنید. میتوانید شیء برگرداندهشده را پیمایش کنید تا نتایج اشیاء awaitable را بهمحض اتمام هرکدام از آنها به دست آورید.
میتوان شیء برگرداندهشده از
as_completed()را بهعنوان یک پیمایشگر ناهمگام یا یک پیمایشگر ساده پیمایش کرد. هنگامی که از پیمایش ناهمگام استفاده میشود، awaitableهایی که در ابتدا ارائه شدهاند، در صورتی که task یا future باشند، بازگشت داده میشوند. این کار مرتبط کردن taskهای از پیش زمانبندیشده با نتایج آنها را آسان میکند. مثال:ipv4_connect = create_task(open_connection("127.0.0.1", 80)) ipv6_connect = create_task(open_connection("::1", 80)) tasks = [ipv4_connect, ipv6_connect] async for earliest_connect in as_completed(tasks): # earliest_connect is done. The result can be obtained by # awaiting it or calling earliest_connect.result() reader, writer = await earliest_connect if earliest_connect is ipv6_connect: print("IPv6 connection established.") else: print("IPv4 connection established.")
در حین تکرار ناهمگام، برای awaitableهای فراهمشده که task یا future نیستند، taskهایی که بهصورت ضمنی ایجاد شدهاند yield داده خواهند شد.
هنگامی که بهعنوان یک پیمایشگر ساده استفاده شود، هر تکرار یک همروال جدید به دست میدهد که نتیجهی awaitable تکمیلشدهی بعدی را بازمیگرداند یا استثنای آن را پرتاب میکند. این الگو با نسخههای قدیمیتر از 3.13 پایتون سازگار است:
ipv4_connect = create_task(open_connection("127.0.0.1", 80)) ipv6_connect = create_task(open_connection("::1", 80)) tasks = [ipv4_connect, ipv6_connect] for next_connect in as_completed(tasks): # next_connect is not one of the original task objects. It must be # awaited to obtain the result value or raise the exception of the # awaitable that finishes next. reader, writer = await next_connect
اگر مهلت زمانی پیش از آنکه همهی awaitableها انجام شوند منقضی شود، یک
TimeoutErrorپرتاب میشود. این استثنا توسط حلقهیasync forدر حین تکرار ناهمگام یا توسط همروالهایی که در حین تکرار ساده تولید میشوند، پرتاب میشود.as_completed()وظایف در حال اجرای awaitableهای ارائهشده را لغو نمیکند: اگر مهلت به پایان برسد یا پیمایش لغو شود، وظایف باقیمانده به اجرا ادامه میدهند.تغییر یافته در نسخهی 3.10: پارامتر loop حذف شد.
منسوخ شده از نسخهی 3.10: اگر تمام اشیای awaitable در پیمایشپذیر aws اشیای شبه-Future نباشند و حلقه رویدادی در حال اجرا وجود نداشته باشد، هشدار از رده خارج شدن نشان داده میشود.
تغییر یافته در نسخهی 3.12: پشتیبانی از تولیدگرهایی که وظایف را yield میکنند، افزوده شد.
تغییر یافته در نسخهی 3.13: نتیجه اکنون میتواند هم بهعنوان یک پیمایشگر ناهمگام و هم بهعنوان یک پیمایشگر ساده استفاده شود (پیشتر فقط یک پیمایشگر ساده بود).
اجرا در نخها¶
- async asyncio.to_thread(func, /, *args, **kwargs)¶
تابع func را بهصورت ناهمگام در یک نخ جداگانه اجرا میکند.
هرگونه *args و **kwargs که برای این تابع ارائه شود، مستقیماً به func ارسال میشود. همچنین
contextvars.Contextجاری منتشر میشود تا متغیرهای زمینه از نخ حلقه رویداد در نخ جداگانه قابل دسترسی باشند.یک همروال برمیگرداند که میتوان آن را await کرد تا نتیجه نهایی func به دست آید.
این تابع همروال عمدتاً برای اجرای توابع/متدهای وابسته به ورودی/خروجی (IO-bound) در نظر گرفته شده است، توابعی که در غیر این صورت، اگر در نخ اصلی اجرا شوند، حلقه رویداد را مسدود میکنند. برای مثال:
def blocking_io(): print(f"start blocking_io at {time.strftime('%X')}") # Note that time.sleep() can be replaced with any blocking # IO-bound operation, such as file operations. time.sleep(1) print(f"blocking_io complete at {time.strftime('%X')}") async def main(): print(f"started main at {time.strftime('%X')}") await asyncio.gather( asyncio.to_thread(blocking_io), asyncio.sleep(1)) print(f"finished main at {time.strftime('%X')}") asyncio.run(main()) # Expected output: # # started main at 19:50:53 # start blocking_io at 19:50:53 # blocking_io complete at 19:50:54 # finished main at 19:50:54
فراخوانی مستقیم
blocking_io()در هر همروالی، حلقه رویداد را برای مدت آن مسدود میکند و باعث افزایش ۱ ثانیهای زمان اجرا میشود. در عوض، با استفاده ازasyncio.to_thread()میتوانیم آن را در یک نخ جداگانه بدون مسدود کردن حلقه رویداد اجرا کنیم.توجه
به دلیل GIL، معمولاً فقط میتوان از
asyncio.to_thread()برای غیرمسدود کردن توابع محدود به ورودی/خروجی (IO-bound) استفاده کرد. با این حال، برای ماژولهای توسعهای که GIL را آزاد میکنند یا پیادهسازیهای جایگزین پایتون که GIL ندارند، میتوان ازasyncio.to_thread()برای توابع محدود به پردازنده (CPU-bound) نیز استفاده کرد.اضافه شده در نسخهی 3.9.
زمانبندی از نخهای دیگر¶
- asyncio.run_coroutine_threadsafe(coro, loop)¶
یک همروال را به حلقه رویداد دادهشده ارسال کنید. نخایمن.
یک
concurrent.futures.Futureبرمیگرداند تا بتوان از یک نخ سیستمعامل دیگر منتظر نتیجه ماند.این تابع برای فراخوانی از یک نخ سیستمعامل متفاوت از نخی که حلقه رویداد در آن اجرا میشود، در نظر گرفته شده است. مثال:
def in_thread(loop: asyncio.AbstractEventLoop) -> None: # Run some blocking IO pathlib.Path("example.txt").write_text("hello world", encoding="utf8") # Create a coroutine coro = asyncio.sleep(1, result=3) # Submit the coroutine to a given loop future = asyncio.run_coroutine_threadsafe(coro, loop) # Wait for the result with an optional timeout argument assert future.result(timeout=2) == 3 async def amain() -> None: # Get the running loop loop = asyncio.get_running_loop() # Run something in a thread await asyncio.to_thread(in_thread, loop)
همچنین میتوان آن را بهصورت معکوس اجرا کرد. مثال:
@contextlib.contextmanager def loop_in_thread() -> Generator[asyncio.AbstractEventLoop]: loop_fut = concurrent.futures.Future[asyncio.AbstractEventLoop]() stop_event = asyncio.Event() async def main() -> None: loop_fut.set_result(asyncio.get_running_loop()) await stop_event.wait() with concurrent.futures.ThreadPoolExecutor(1) as tpe: complete_fut = tpe.submit(asyncio.run, main()) for fut in concurrent.futures.as_completed((loop_fut, complete_fut)): if fut is loop_fut: loop = loop_fut.result() try: yield loop finally: loop.call_soon_threadsafe(stop_event.set) else: fut.result() # Create a loop in another thread with loop_in_thread() as loop: # Create a coroutine coro = asyncio.sleep(1, result=3) # Submit the coroutine to a given loop future = asyncio.run_coroutine_threadsafe(coro, loop) # Wait for the result with an optional timeout argument assert future.result(timeout=2) == 3
اگر در همروال استثنایی پرتاب شود، به Future برگرداندهشده اطلاع داده خواهد شد. همچنین میتوان از آن برای لغو وظیفه در حلقه رویداد استفاده کرد:
try: result = future.result(timeout) except TimeoutError: print('The coroutine took too long, cancelling the task...') future.cancel() except Exception as exc: print(f'The coroutine raised an exception: {exc!r}') else: print(f'The coroutine returned: {result!r}')
بخش همروندی و چندریسمانی مستندات را ببینید.
برخلاف سایر توابع asyncio، این تابع نیاز دارد که آرگومان loop بهصورت صریح ارسال شود.
اضافه شده در نسخهی 3.5.1.
دروننگری¶
- asyncio.current_task(loop=None)¶
نمونهی در حال اجرای
Taskرا برمیگرداند، یا اگر هیچ وظیفهای در حال اجرا نباشد،Noneرا برمیگرداند.اگر loop برابر
Noneباشد، ازget_running_loop()برای گرفتن حلقه جاری استفاده میشود.اضافه شده در نسخهی 3.7.
- asyncio.all_tasks(loop=None)¶
مجموعهای از اشیاء
Taskکه هنوز تمامنشدهاند و توسط حلقه اجرا میشوند را برمیگرداند.اگر loop برابر
Noneباشد، برای گرفتن حلقهی جاری ازget_running_loop()استفاده میشود.اضافه شده در نسخهی 3.7.
- asyncio.iscoroutine(obj)¶
اگر obj یک شیء همروال باشد،
Trueبرمیگرداند.اضافه شده در نسخهی 3.4.
شیء Task¶
- class asyncio.Task(coro, *, loop=None, name=None, context=None, eager_start=False)¶
یک شیء
Future-مانندکه یک همروال پایتون را اجرا میکند. نخایمن نیست.از Taskها برای اجرای همروالها در حلقههای رویداد استفاده میشود. اگر یک همروال روی یک Future await کند، Task اجرای همروال را معلق میکند و منتظر کامل شدن Future میماند. هنگامی که Future انجامشده باشد، اجرای همروال دربرگرفتهشده از سر گرفته میشود.
حلقههای رویداد از زمانبندی مشارکتی استفاده میکنند: یک حلقه رویداد در هر زمان یک Task را اجرا میکند. هنگامی که یک Task برای تکمیل شدن یک Future await میکند، حلقه رویداد Taskهای دیگر و کالبکها را اجرا میکند یا عملیات ورودی/خروجی انجام میدهد.
برای ایجاد Taskها، از تابع سطح بالای
asyncio.create_task()یا توابع سطح پایینloop.create_task()یاensure_future()استفاده کنید. نمونهسازی دستی Taskها توصیه نمیشود.برای لغو یک Task در حال اجرا، از متد
cancel()استفاده کنید. فراخوانی آن موجب میشود که Task استثنایCancelledErrorرا به درون همروال پوشیدهشده پرتاب کند. اگر یک همروال در حین لغو، روی یک شیء Future در حال await باشد، شیء Future لغو خواهد شد.میتوانید از
cancelled()برای بررسی اینکه Task لغو شده است یا خیر استفاده کنید. اگر همروال پوشیدهشده استثنایCancelledErrorرا سرکوب نکرده باشد و واقعاً لغو شده باشد، این متدTrueبرمیگرداند.asyncio.TaskازFutureهمهی APIهای آن را به ارث میبرد، بهجزFuture.set_result()وFuture.set_exception().یک آرگومان context اختیاری فقط کلیدواژهای به شما امکان میدهد یک
contextvars.Contextسفارشی را برای اجرای coro در آن تعیین کنید. اگر context ارائه نشود، Task زمینه جاری را کپی میکند و بعداً همروال خود را در زمینه کپیشده اجرا میکند.یک آرگومان اختیاری و فقط کلیدواژهای به نام eager_start امکان شروع فوری اجرای
asyncio.Taskرا در زمان ایجاد وظیفه فراهم میکند. اگر رویTrueتنظیم شده باشد و حلقه رویداد در حال اجرا باشد، وظیفه اجرای همروال را بلافاصله آغاز میکند، تا نخستین باری که همروال مسدود شود. اگر همروال بدون مسدود شدن بازگشت کند یا استثنایی پرتاب کند، وظیفه بهصورت فوری به پایان میرسد و در حلقه رویداد زمانبندی نمیشود.وظایف نسبت به نوع برگشتی همروالهای دربرگرفتهشدهی خود عام هستند.
تغییر یافته در نسخهی 3.7: پشتیبانی از ماژول
contextvarsافزوده شد.تغییر یافته در نسخهی 3.8: پارامتر name افزوده شد.
منسوخ شده از نسخهی 3.10: اگر loop مشخص نشده باشد و هیچ حلقه رویدادی در حال اجرا وجود نداشته باشد، هشدار منسوخشدن نشان داده میشود.
تغییر یافته در نسخهی 3.11: پارامتر context افزوده شد.
تغییر یافته در نسخهی 3.12: پارامتر eager_start اضافه شد.
- done()¶
اگر Task انجامشده باشد،
Trueرا برمیگرداند.یک وظیفه زمانی انجامشده است که همروال دربرگرفتهشدهی آن، یا مقداری را برگردانده باشد، یا استثنایی را پرتاب کرده باشد، یا آن وظیفه لغو شده باشد.
- result()¶
نتیجهی Task را برمیگرداند.
اگر Task انجامشده باشد، نتیجه همروال پوشیدهشده برگردانده میشود (یا اگر همروال استثنایی را پرتاب کرده باشد، آن استثنا دوباره پرتاب میشود.)
اگر Task لغوشده باشد، این متد استثنای
CancelledErrorرا پرتاب میکند.اگر نتیجهی Task هنوز در دسترس نباشد، این متد یک استثنای
InvalidStateErrorپرتاب میکند.
- exception()¶
استثنای Task را برمیگرداند.
اگر همروال پوشیدهشده استثنایی پرتاب کرد، آن استثنا برگردانده میشود. اگر همروال پوشیدهشده بهطور عادی بازگشت کرد، این متد
Noneرا برمیگرداند.اگر Task لغوشده باشد، این متد استثنای
CancelledErrorرا پرتاب میکند.اگر Task هنوز انجامشده نباشد، این متد استثنای
InvalidStateErrorرا پرتاب میکند.
- add_done_callback(callback, *, context=None)¶
یک کالبک اضافه کنید تا هنگامی که Task انجامشده باشد اجرا شود.
این متد تنها باید در کد سطح پایین مبتنی بر کالبک استفاده شود.
برای جزئیات بیشتر، مستندات
Future.add_done_callback()را ببینید.
- remove_done_callback(callback)¶
callback را از فهرست کالبکها حذف کنید.
این متد تنها باید در کد سطح پایین مبتنی بر کالبک استفاده شود.
برای جزئیات بیشتر، به مستندات
Future.remove_done_callback()مراجعه کنید.
- get_stack(*, limit=None)¶
فهرست فریمهای پشته (stack frames) برای این Task را برمیگرداند.
اگر همروال دربرگرفتهشده انجامنشده باشد، پشتهای که در آن معلق است برگردانده میشود. اگر همروال با موفقیت به پایان رسیده باشد یا لغو شده باشد، یک فهرست خالی برگردانده میشود. اگر همروال با یک استثنا خاتمه یافته باشد، فهرست فریمهای ردگیری پشته برگردانده میشود.
فریمها همیشه از قدیمیترین به جدیدترین مرتب شدهاند.
تنها یک فریم پشته برای یک همروال تعلیقشده برگردانده میشود.
آرگومان اختیاری limit حداکثر تعداد فریمهای بازگشتی را تنظیم میکند؛ بهطور پیشفرض همهی فریمهای موجود بازگردانده میشوند. ترتیب فهرست بازگشتی بسته به اینکه یک پشته یا یک ردگیری بازگردانده شود، متفاوت است: جدیدترین فریمهای یک پشته بازگردانده میشوند، اما قدیمیترین فریمهای یک ردگیری بازگردانده میشوند. (این با رفتار ماژول traceback مطابقت دارد.)
- print_stack(*, limit=None, file=None)¶
پشته یا ردگیری پشتهی این Task را چاپ میکند.
این، خروجی مشابهی با خروجی ماژول traceback برای فریمهای بازیابیشده توسط
get_stack()تولید میکند.آرگومان limit مستقیماً به
get_stack()ارسال میشود.آرگومان file یک جریان ورودی/خروجی است که خروجی به آن نوشته میشود؛ بهطور پیشفرض خروجی به
sys.stdoutنوشته میشود.
- get_coro()¶
شیء همروالِ دربرگرفتهشده توسط
Taskرا برمیگرداند.توجه
این
Noneرا برای Taskهایی که از قبل بهصورت حریصانه کامل شدهاند، بازمیگرداند. Eager Task Factory را ببینید.اضافه شده در نسخهی 3.8.
تغییر یافته در نسخهی 3.12: اجرای مشتاقانهی وظیفه (eager task execution) که بهتازگی اضافهشده است، به این معناست که نتیجه ممکن است
Noneباشد.
- get_context()¶
شیء
contextvars.Contextمرتبط با وظیفه را برمیگرداند.اضافه شده در نسخهی 3.12.
- get_name()¶
نام Task را برمیگرداند.
اگر نامی بهطور صریح به Task اختصاص داده نشده باشد، پیادهسازی پیشفرض Task در asyncio، در هنگام نمونهسازی یک نام پیشفرض تولید میکند.
اضافه شده در نسخهی 3.8.
- set_name(value)¶
نام Task را تنظیم کنید.
آرگومان value میتواند هر شیءای باشد که سپس به رشته تبدیل میشود.
در پیادهسازی پیشفرض Task، نام در خروجی
repr()یک شیء task قابل مشاهده خواهد بود.اضافه شده در نسخهی 3.8.
- cancel(msg=None)¶
درخواست لغو Task را بدهید.
اگر Task از پیش انجامشده یا لغوشده باشد،
Falseرا برمیگرداند، در غیر این صورتTrueرا برمیگرداند.این متد ترتیبی میدهد که استثنای
CancelledErrorدر چرخهی بعدی حلقهی رویداد به همروال پوشیدهشده پرتاب شود.سپس همروال این فرصت را دارد که پاکسازی کند یا حتی با مهار استثنا از طریق یک بلوک
try... ...except CancelledError...finally، درخواست را رد کند. بنابراین، برخلافFuture.cancel()،Task.cancel()تضمین نمیکند که Task لغو شود، اگرچه مهار کامل لغو رایج نیست و بهطور فعال نهی شده است. اگر همروال با این حال تصمیم بگیرد لغو را مهار کند، باید علاوه بر گرفتن استثنا،Task.uncancel()را نیز فراخوانی کند.تغییر یافته در نسخهی 3.9: پارامتر msg اضافه شد.
تغییر یافته در نسخهی 3.11: پارامتر
msgاز وظیفه لغوشده به awaitکنندهی آن منتقل میشود.مثال زیر نشان میدهد که همروالها چگونه میتوانند درخواست لغو را رهگیری کنند:
async def cancel_me(): print('cancel_me(): before sleep') try: # Wait for 1 hour await asyncio.sleep(3600) except asyncio.CancelledError: print('cancel_me(): cancel sleep') raise finally: print('cancel_me(): after sleep') async def main(): # Create a "cancel_me" Task task = asyncio.create_task(cancel_me()) # Wait for 1 second await asyncio.sleep(1) task.cancel() try: await task except asyncio.CancelledError: print("main(): cancel_me is cancelled now") asyncio.run(main()) # Expected output: # # cancel_me(): before sleep # cancel_me(): cancel sleep # cancel_me(): after sleep # main(): cancel_me is cancelled now
- cancelled()¶
اگر Task لغوشده باشد،
Trueرا برمیگرداند.Task زمانی لغو میشود که لغو با
cancel()درخواست شده باشد و همروال دربرگرفتهشده، استثنایCancelledErrorپرتابشده به درون آن را منتشر کرده باشد.
- uncancel()¶
شمار درخواستهای لغو برای این Task را کاهش میدهد.
تعداد باقیماندهی درخواستهای لغو را برمیگرداند.
توجه داشته باشید که پس از کامل شدن اجرای یک وظیفهی لغوشده، فراخوانیهای بعدی
uncancel()بیاثر خواهند بود.اضافه شده در نسخهی 3.11.
این متد توسط بخشهای داخلی asyncio استفاده میشود و انتظار نمیرود توسط کد کاربر نهایی استفاده شود. بهویژه، اگر یک Task با موفقیت از حالت لغو خارج شود، این امر به عناصر همروندی ساختاریافته (structured concurrency) مانند گروههای وظیفه (Task groups) و
asyncio.timeout()اجازه میدهد به اجرای خود ادامه دهند و لغو را به بلوک ساختاریافته مربوطه محدود کنند. برای مثال:async def make_request_with_timeout(): try: async with asyncio.timeout(1): # Structured block affected by the timeout: await make_request() await make_another_request() except TimeoutError: log("There was a timeout") # Outer code not affected by the timeout: await unrelated_code()
در حالی که ممکن است بلوک حاوی
make_request()وmake_another_request()به دلیل مهلت زمانی لغو شود،unrelated_code()باید حتی در صورت وقوع مهلت زمانی به اجرای خود ادامه دهد. این کار باuncancel()پیادهسازی شده است. مدیران زمینهTaskGroupازuncancel()به شیوهای مشابه استفاده میکنند.اگر کد کاربر نهایی به هر دلیلی با گرفتن
CancelledErrorلغو را مهار میکند، باید این متد را فراخوانی کند تا وضعیت لغو را حذف کند.هنگامی که این متد شمار لغو را به صفر کاهش میدهد، متد بررسی میکند که آیا یک فراخوانی پیشین
cancel()ترتیبی برای پرتابCancelledErrorبه درون وظیفه داده بود یا خیر. اگر هنوز پرتاب نشده باشد، آن ترتیب لغو خواهد شد (با بازنشانی پرچم داخلی_must_cancel).
تغییر یافته در نسخهی 3.13: تغییر کرد تا درخواستهای لغو در انتظار، پس از رسیدن به صفر پس گرفته شوند.
- cancelling()¶
تعداد درخواستهای لغو در انتظار برای این Task را برمیگرداند، یعنی تعداد فراخوانیهای
cancel()منهای تعداد فراخوانیهایuncancel().توجه داشته باشید که اگر این عدد بزرگتر از صفر باشد اما Task هنوز در حال اجرا باشد،
cancelled()همچنانFalseرا برمیگرداند. این به این دلیل است که این عدد میتواند با فراخوانیuncancel()کاهش یابد، که اگر درخواستهای لغو به صفر برسند، ممکن است در نهایت منجر به لغو نشدن Task شود.این متد توسط اجزای داخلی asyncio استفاده میشود و انتظار نمیرود که توسط کد کاربر نهایی استفاده شود. برای جزئیات بیشتر
uncancel()را ببینید.اضافه شده در نسخهی 3.11.