هم‌روال‌ها و وظایف

این بخش، مروری بر 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؛

  • یک شیء هم‌روال: شیءای که با فراخوانی یک تابع هم‌روال برگردانده می‌شود.

Generator-based coroutines, created with types.coroutine(), are covered by neither term and are not supported by asyncio.

وظایف

وظایف برای زمان‌بندی هم‌روال‌ها به‌صورت همزمان استفاده می‌شوند.

هنگامی که یک هم‌روال با توابعی مانند 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.TaskGroup which 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 given coro and raise RuntimeError.

تغییر یافته در نسخه‌ی 3.13: اگر گروه وظیفه فعال نیست، هم‌روال داده‌شده را ببندید.

تغییر یافته در نسخه‌ی 3.14: تمام kwargs را به loop.create_task() منتقل می‌کند

cancel()

Cancel the task group. This is a non-exceptional, early exit of the task group's lifetime -- useful once the group's goal has been met or its services no longer needed.

cancel() will be called on any tasks in the group that aren't yet done, as well as the parent (body) of the group. The task group context manager will exit without asyncio.CancelledError being raised.

If cancel() is called before entering the task group, the group will be cancelled upon entry. This is useful for patterns where one piece of code passes an unused asyncio.TaskGroup instance to another in order to have the ability to cancel anything run within the group.

cancel() is idempotent and may be called after the task group has already exited.

Some ways to use cancel():

  • call it from the task group body based on some condition or event

  • pass the task group instance to child tasks via create_task(), allowing a child task to conditionally cancel the entire group

  • pass the task group instance or bound cancel() method to some other task before opening the task group, allowing remote cancellation

اضافه شده در نسخه‌ی 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()}")

A few points to keep in mind when using task groups:

  • The async with statement will wait for all tasks in the group to finish. While waiting, new tasks may still be added to the group (for example, by passing tg into one of the coroutines and calling tg.create_task() in that coroutine); once the last task has finished and the async with block is exited, no new tasks may be added.

  • Termination of the entire task group may be requested with tg.cancel(), based on some condition.

  • If the group is shut down (e.g. because another task failed) before a newly created task has started running, the task is cancelled without its coroutine executing at all, not even to its first await. To guarantee that the coroutine starts, create the task eagerly with eager_start=True or use asyncio.eager_task_factory(). For example:

    async def job():
        print("job started")  # never printed
        try:
            await asyncio.sleep(1)
        finally:
            print("job cleaned up")  # never printed
    
    async def main():
        async with asyncio.TaskGroup() as tg:
            tg.create_task(job())
            raise RuntimeError  # shuts down the group before job() runs
    

    With tg.create_task(job(), eager_start=True), job() runs up to the await, is cancelled there, and both messages are printed.

When any of the tasks belonging to the group fails with an exception other than asyncio.CancelledError (or the body of the async with statement exits with an exception, which is treated the same way):

  • The first time this happens, the remaining tasks in the group are cancelled and then waited for, and no further tasks can be added to the group. If the body of the async with statement is still active (i.e., __aexit__() hasn't been called yet), the task directly containing the async with statement is also cancelled. The resulting asyncio.CancelledError will interrupt an await, but it will not bubble out of the containing async with statement.

  • Once all tasks have finished, the non-cancellation exceptions -- including the exception the body exited with, unless it is asyncio.CancelledError -- are combined in an ExceptionGroup or BaseExceptionGroup (as appropriate; see their documentation), which is then raised.

  • Some exceptions are treated specially: if any task fails with KeyboardInterrupt or SystemExit, the task group still cancels the remaining tasks and waits for them, but then the initial KeyboardInterrupt or SystemExit is re-raised instead of ExceptionGroup or BaseExceptionGroup. Additionally, if the body of the async with statement raises GeneratorExit and none of the other tasks raise exceptions that would be reported, the GeneratorExit is re-raised.

گروه‌های وظیفه مراقب هستند که لغو داخلیِ استفاده‌شده برای «بیدار کردن» __aexit__() خود را با درخواست‌های لغو برای وظیفهی که در آن در حال اجرا هستند و از سوی طرف‌های دیگر مطرح شده‌اند، اشتباه نگیرند. به‌ویژه، هنگامی که یک گروه وظیفه از نظر نحوی در گروه دیگری تودرتو شده باشد و هر دو همزمان در یکی از وظایف فرزند خود با استثنا مواجه شوند، گروه وظیفه داخلی استثناهای خود را پردازش می‌کند و سپس گروه وظیفه خارجی لغو دیگری را دریافت می‌کند و استثناهای خود را پردازش می‌کند.

In the case where a task group is cancelled externally and also must raise an ExceptionGroup, it will call the parent task's cancel() method. This ensures that a asyncio.CancelledError will be raised at the next await, so the cancellation is not lost. Task groups also preserve the cancellation count reported by asyncio.Task.cancelling().

تغییر یافته در نسخه‌ی 3.13: مدیریت بهتر لغوهای همزمان داخلی و خارجی و حفظ صحیح تعداد لغوها.

تغییر یافته در نسخه‌ی 3.15: Addition of the special case for GeneratorExit.

توقف

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(arg)

از یک شیء awaitable در برابر لغو شدن محافظت کنید.

If arg is a coroutine it is automatically scheduled as a 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: Deprecation warning is emitted if arg is not Future-like object and there is no running event loop.

مهلت‌های زمانی

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() باشد، مهلت زمانی در تکرار بعدی حلقه رویداد فعال خواهد شد.

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(fut, timeout)

Wait for the fut awaitable to complete with a timeout.

timeout می‌تواند None یا یک عدد float یا int به‌عنوان تعداد ثانیه‌های انتظار باشد. اگر timeout برابر None باشد، تا زمانی که future تکمیل شود، مسدود می‌شود.

If a timeout occurs, it cancels fut and raises TimeoutError.

To prevent fut from being cancelled, wrap it in shield().

این تابع تا زمانی که فیوچر (future) به‌طور واقعی لغو شود، صبر می‌کند، بنابراین کل زمان انتظار ممکن است از timeout فراتر رود. اگر در حین لغو استثنایی رخ دهد، آن استثنا انتشار می‌یابد.

If the wait is cancelled, the future fut is also cancelled.

مثال:

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: When fut is cancelled due to a timeout, wait_for waits for fut to be cancelled. Previously, it raised TimeoutError immediately.

تغییر یافته در نسخه‌ی 3.10: پارامتر loop حذف شد.

تغییر یافته در نسخه‌ی 3.11: TimeoutError را به‌جای asyncio.TimeoutError پرتاب می‌کند.

تغییر یافته در نسخه‌ی 3.12: Implemented using asyncio.timeout(), a coroutine passed as fut is no longer wrapped in a Task when timeout is positive.

اولیه‌های انتظار

async asyncio.wait(fs, *, timeout=None, return_when=ALL_COMPLETED)

Run Future and Task instances in the fs iterable concurrently and block until the condition specified by return_when.

The fs iterable must not be empty.

دو مجموعه از Tasks/Futures را برمی‌گرداند: (done, pending).

استفاده:

done, pending = await asyncio.wait(fs)

timeout (یک float یا int)، در صورت مشخص بودن، می‌تواند برای کنترل حداکثر تعداد ثانیه‌های انتظار پیش از بازگشت استفاده شود.

توجه داشته باشید که این تابع TimeoutError را پرتاب نمی‌کند. Futureها یا Taskهایی که هنگام فرا رسیدن مهلت زمانی انجام نشده‌اند، به‌سادگی در مجموعه دوم برگردانده می‌شوند.

return_when نشان می‌دهد که این تابع چه زمانی باید بازگشت کند. این مقدار باید یکی از ثابت‌های زیر باشد:

ثابت

توضیح

asyncio.FIRST_COMPLETED

تابع هنگامی بازگشت خواهد کرد که هر فیوچر به پایان برسد یا لغو شود.

asyncio.FIRST_EXCEPTION

این تابع هنگامی بازگشت می‌کند که هر فیوچر با پرتاب یک استثنا به پایان برسد. اگر هیچ فیوچری استثنا پرتاب نکند، معادل ALL_COMPLETED خواهد بود.

asyncio.ALL_COMPLETED

تابع زمانی بازگشت می‌کند که همه‌ی آینده‌نماها (futures) پایان یابند یا لغو شوند.

برخلاف wait_for()، wait() در صورت وقوع مهلت زمانی، آینده‌نماها (futures) را لغو نمی‌کند.

If wait() is cancelled, the futures in fs are not cancelled and continue to run.

تغییر یافته در نسخه‌ی 3.10: پارامتر loop حذف شد.

تغییر یافته در نسخه‌ی 3.11: ارسال اشیای هم‌روال به wait() به‌صورت مستقیم ممنوع است.

تغییر یافته در نسخه‌ی 3.12: پشتیبانی از تولیدگرهایی که وظایف را yield می‌کنند، افزوده شد.

asyncio.as_completed(fs, *, timeout=None)

Run awaitable objects in the fs iterable concurrently. The returned object can be iterated to obtain the results of the awaitables as they finish.

می‌توان شیء برگردانده‌شده از 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: Deprecation warning is emitted if not all awaitable objects in the fs iterable are Future-like objects and there is no running event loop.

تغییر یافته در نسخه‌ی 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.

تغییر یافته در نسخه‌ی 3.12: Generator-based coroutines are no longer supported, and False is returned for them.

شیء 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ها توصیه نمی‌شود.

To cancel a running Task use the cancel() method. Calling it will cause the Task to throw a CancelledError exception into the wrapped coroutine. If a coroutine is awaiting on a future-like object during cancellation, the awaited object will be cancelled.

می‌توانید از 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() را نیز فراخوانی کند.

If the Task being cancelled is currently awaiting on a future-like object, that awaited object will also be cancelled. This cancellation propagates down the entire chain of awaited objects.

تغییر یافته در نسخه‌ی 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.