GeezerVison is showing python.github.io — همروالها و وظایف
همروالها و وظایف¶
این بخش، مروری بر 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')}")
زمانبندی و خروجی باید مانند نسخهی پیشین یکسان باشند.
میگوییم که یک شیء در صورتی یک شیء 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())
مهم
در این مستندات، اصطلاح «همروال» میتواند برای دو مفهوم بسیار مرتبط بهکار رود:
وظایف
وظایف برای زمانبندی همروالها بهصورت همزمان استفاده میشوند.
هنگامی که یک همروال با توابعی مانند 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)
توجه داشته باشید که این رویکرد هرگز وظایف را await نمیکند، بنابراین اگر یک وظیفه شکست بخورد، استثنای آن هرگز بازیابی نمیشود و asyncio پیامی "Task exception was never retrieved" را ثبت میکند وقتی که وظیفه زبالهروب میشود. برای جلوگیری از این، از asyncio.TaskGroup استفاده کنید که یک ارجاع قوی به هر وظیفه نگه میدارد، آنها را await میکند و استثنای آنها را انتقال میدهد:
async with asyncio.TaskGroup() as tg:
for i in range(10):
tg.create_task(some_coro(param=i))
تغییر یافته در نسخهی 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() نیز فراخوانی شود تا وضعیت لغو بهطور کامل حذف شود.
گروههای وظیفه، یک API برای ایجاد وظیفه را با روشی راحت و مطمئن برای منتظر ماندن تا پایانیافتن تمام وظایف گروه ترکیب میکنند.
-
class asyncio.TaskGroup¶
یک مدیر زمینه ناهمگام که گروهی از وظایف را نگه میدارد. میتوان وظایف را با استفاده از create_task() به گروه اضافه کرد. هنگام خروج مدیر زمینه، همه وظایف await میشوند.
اضافه شده در نسخهی 3.11.
-
create_task(coro, *, name=None, context=None, eager_start=None, **kwargs)¶
یک وظیفه در این گروه وظیفه ایجاد کنید. امضا با asyncio.create_task() مطابقت دارد. اگر گروه وظیفه غیرفعال باشد (مثلا هنوز وارد نشده، قبلاً تمام شده، یا در فرآیند خاموش شدن)، ما coro داده شده را میبندیم و RuntimeError را پرتاب میکنیم.
تغییر یافته در نسخهی 3.13: اگر گروه وظیفه فعال نیست، همروال دادهشده را ببندید.
-
cancel()¶
گروه وظیفه را لغو کنید. این یک خروج زودهنگام و غیرخطایی از چرخهی عمر گروه وظیفه است؛ و زمانی مفید است که هدف گروه برآورده شده باشد یا خدمات آن دیگر نیازی نباشد.
متد cancel() روی هر وظیفهای در گروه که هنوز تمام نشده است و همچنین والد (بدنه) گروه فراخوانی خواهد شد. مدیر زمینهی گروه وظیفه بدون بالا آمدن asyncio.CancelledError خارج خواهد شد.
اگر متد cancel() قبل از ورود به گروه وظیفه فراخوانی شود، گروه پس از ورود لغو خواهد شد. این کار برای الگوهایی مفید است که در آن یک تکه کد یک نمونهی asyncio.TaskGroup استفادهنشده را به تکهی دیگری منتقل میکند تا توانایی لغو هر چیز در حال اجرا درون گروه را داشته باشد.
cancel() همتوان است و ممکن است پس از خروج گروه وظیفه نیز فراخوانی شود.
برخی از راهها برای استفاده از متد cancel():
آن را بر اساس برخی شرایط یا رویداد از بدنههی گروه وظیفه فراخوانی کنید
نمونهی گروه وظیفه را از طریق create_task() به وظایف فرزند ارسال کنید، که به وظیفهی فرزند اجازه میدهد کل گروه را به طور شرطی لغو کند
نمونهی گروه وظیفه یا متد متصل cancel() را پیش از گشودن گروه وظیفه به وظیفهی دیگری ارسال کنید، که امکان لغو از راه دور را فراهم میکند
اضافه شده در نسخهی 3.15.
مثال:
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() در آن همروال). همچنین این فرصت وجود دارد که بر اساس شرایطی، درخواست خاتمهی کل گروه وظایف با tg.cancel() داده شود. هنگامی که آخرین وظیفه به پایان رسید و از بلوک 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 مانند پاراگراف قبلی اعمال میشود. یک حالت خاص اضافی نیز فقط برای بدنهی async with در نظر گرفته شده است: اگر این بخش GeneratorExit را بالا ببرد و هیچکدام از وظایف دیگر استثناهایی که باید گزارش شوند را بالا نبرند، آنگاه GeneratorExit دوباره بالا برده میشود.
گروههای وظیفه مراقب هستند که لغو داخلیِ استفادهشده برای «بیدار کردن» __aexit__() خود را با درخواستهای لغو برای وظیفهی که در آن در حال اجرا هستند و از سوی طرفهای دیگر مطرح شدهاند، اشتباه نگیرند. بهویژه، هنگامی که یک گروه وظیفه از نظر نحوی در گروه دیگری تودرتو شده باشد و هر دو همزمان در یکی از وظایف فرزند خود با استثنا مواجه شوند، گروه وظیفه داخلی استثناهای خود را پردازش میکند و سپس گروه وظیفه خارجی لغو دیگری را دریافت میکند و استثناهای خود را پردازش میکند.
در حالتی که یک گروه وظیفه از بیرون لغو میشود و همچنین باید یک ExceptionGroup را پرتاب کند، متد cancel() مربوط به وظیفهی والد (parent task) را فراخوانی میکند. این کار تضمین میکند که یک asyncio.CancelledError در await بعدی پرتاب میشود، بنابراین لغو از دست نمیرود.
گروههای Task تعداد لغو گزارششده توسط asyncio.Task.cancelling() را حفظ میکنند.
تغییر یافته در نسخهی 3.13: مدیریت بهتر لغوهای همزمان داخلی و خارجی و حفظ صحیح تعداد لغوها.
-
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-مانند نباشند و هیچ حلقهی رویدادی در حال اجرا وجود نداشته باشد، هشدار از رده خارج شدن نشان داده میشود.
-
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)
معادل است با:
به جز اینکه اگر همروال حاوی آن لغو شود، 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 تبدیل میکند که میتوان آن را گرفت و مدیریت کرد.
نمونهای از گرفتن 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() → float | None¶
مهلت فعلی را برمیگرداند، یا اگر مهلت فعلی تنظیمنشده باشد None را برمیگرداند.
-
reschedule(when: float | None)¶
مهلت را دوباره زمانبندی کنید.
-
expired() → bool¶
برمیگرداند که آیا مدیر زمینه از مهلت خود گذشته است (منقضیشده است).
مثال:
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 تکمیل شود، مسدود میشود.
اگر مهلت زمانی رخ دهد، aw را لغو میکند و TimeoutError را پرتاب میکند.
برای جلوگیری از لغو شدن aw، آن را در 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.12: با استفاده از asyncio.timeout() پیادهسازی شده، یک همروال که به عنوان aw پاس داده شده است، وقتی timeout مثبت باشد، دیگر در یک Task پوشانده نمیشود.
-
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) نیز استفاده کرد.
-
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() برای گرفتن حلقه جاری استفاده میشود.
-
asyncio.all_tasks(loop=None)¶
مجموعهای از اشیاء Task که هنوز تمامنشدهاند و توسط حلقه اجرا میشوند را برمیگرداند.
اگر loop برابر None باشد، برای گرفتن حلقهی جاری از get_running_loop() استفاده میشود.
-
asyncio.iscoroutine(obj)¶
اگر obj یک شیء همروال باشد، True برمیگرداند.
-
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 را در coroutine پوشاندهشده ایجاد کند. اگر یک coroutine هنگام لغو در حال انتظار برای یک شیء شبه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.12: اجرای مشتاقانهی وظیفه (eager task execution) که بهتازگی اضافهشده است، به این معناست که نتیجه ممکن است None باشد.
-
get_context()¶
شیء contextvars.Context مرتبط با وظیفه را برمیگرداند.
اضافه شده در نسخهی 3.12.
-
get_name()¶
نام Task را برمیگرداند.
اگر نامی بهطور صریح به Task اختصاص داده نشده باشد، پیادهسازی پیشفرض Task در asyncio، در هنگام نمونهسازی یک نام پیشفرض تولید میکند.
-
set_name(value)¶
نام Task را تنظیم کنید.
آرگومان value میتواند هر شیءای باشد که سپس به رشته تبدیل میشود.
در پیادهسازی پیشفرض Task، نام در خروجی repr() یک شیء task قابل مشاهده خواهد بود.
-
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.
© حق نشر 2001 Python Software Foundation.
این صفحه تحت مجوز بنیاد نرمافزار پایتون نسخه ۲ منتشر شده است.
مثالها، دستورالعملها، و سایر کدهای موجود در مستندات همچنین تحت مجوز بدون بند BSD منتشر شدهاند.
برای اطلاعات بیشتر به تاریخچه و مجوز مراجعه کنید.
بنیاد نرمافزار پایتون یک شرکت غیرانتفاعی است.
لطفاً کمک مالی کنید.
آخرین بهروزرسانی در نوامبر 12, 2026 (06:19 UTC).
آیا اشکالی یافتید؟
ساخته شده با Sphinx 9.1.0.
|