Coroutines and Tasks¶
This section outlines high-level asyncio APIs to work with coroutinesand Tasks.
Coroutines¶
Source code:Lib/asyncio/coroutines.py
Coroutines declared with the async/await syntax is thepreferred way of writing asyncio applications. For example, the followingsnippet of code prints “hello”, waits 1 second,and then prints “world”:
>>>importasyncio>>>asyncdefmain():...print('hello')...awaitasyncio.sleep(1)...print('world')>>>asyncio.run(main())helloworld
Note that simply calling a coroutine will not schedule it tobe executed:
>>>main()<coroutine object main at 0x1053bb7c8>
To actually run a coroutine, asyncio provides the following mechanisms:
The
asyncio.run()
function to run the top-levelentry point “main()” function (see the above example.)Awaiting on a coroutine. The following snippet of code willprint “hello” after waiting for 1 second, and then print “world”after waiting foranother 2 seconds:
importasyncioimporttimeasyncdefsay_after(delay,what):awaitasyncio.sleep(delay)print(what)asyncdefmain():print(f"started at{time.strftime('%X')}")awaitsay_after(1,'hello')awaitsay_after(2,'world')print(f"finished at{time.strftime('%X')}")asyncio.run(main())
Expected output:
startedat17:13:52helloworldfinishedat17:13:55
The
asyncio.create_task()
function to run coroutinesconcurrently as asyncioTasks
.Let’s modify the above example and run two
say_after
coroutinesconcurrently:asyncdefmain():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.)awaittask1awaittask2print(f"finished at{time.strftime('%X')}")
Note that expected output now shows that the snippet runs1 second faster than before:
startedat17:14:32helloworldfinishedat17:14:34
The
asyncio.TaskGroup
class provides a more modernalternative tocreate_task()
.Using this API, the last example becomes:asyncdefmain():asyncwithasyncio.TaskGroup()astg: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')}")
The timing and output should be the same as for the previous version.
Added in version 3.11:
asyncio.TaskGroup
.
Awaitables¶
We say that an object is anawaitable object if it can be usedin anawait
expression. Many asyncio APIs are designed toaccept awaitables.
There are three main types ofawaitable objects:coroutines,Tasks, andFutures.
Coroutines
Python coroutines areawaitables and therefore can be awaited fromother coroutines:
importasyncioasyncdefnested():return42asyncdefmain():# 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(awaitnested())# will print "42".asyncio.run(main())
Important
In this documentation the term “coroutine” can be used fortwo closely related concepts:
acoroutine function: an
asyncdef
function;acoroutine object: an object returned by calling acoroutine function.
Tasks
Tasks are used to schedule coroutinesconcurrently.
When a coroutine is wrapped into aTask with functions likeasyncio.create_task()
the coroutine is automaticallyscheduled to run soon:
importasyncioasyncdefnested():return42asyncdefmain():# 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:awaittaskasyncio.run(main())
Futures
AFuture
is a speciallow-level awaitable object thatrepresents aneventual result of an asynchronous operation.
When a Future object isawaited it means that the coroutine willwait until the Future is resolved in some other place.
Future objects in asyncio are needed to allow callback-based codeto be used with async/await.
Normallythere is no need to create Future objects at theapplication level code.
Future objects, sometimes exposed by libraries and some asyncioAPIs, can be awaited:
asyncdefmain():awaitfunction_that_returns_a_future_object()# this is also valid:awaitasyncio.gather(function_that_returns_a_future_object(),some_python_coroutine())
A good example of a low-level function that returns a Future objectisloop.run_in_executor()
.
Creating Tasks¶
Source code:Lib/asyncio/tasks.py
- asyncio.create_task(coro,*,name=None,context=None)¶
Wrap thecorocoroutine into a
Task
and schedule its execution. Return the Task object.Ifname is not
None
, it is set as the name of the task usingTask.set_name()
.An optional keyword-onlycontext argument allows specifying acustom
contextvars.Context
for thecoro to run in.The current context copy is created when nocontext is provided.The task is executed in the loop returned by
get_running_loop()
,RuntimeError
is raised if there is no running loop incurrent thread.Note
asyncio.TaskGroup.create_task()
is a new alternativeleveraging structural concurrency; it allows for waitingfor a group of related tasks with strong safety guarantees.Important
Save a reference to the result of this function, to avoida task disappearing mid-execution. The event loop only keepsweak references to tasks. A task that isn’t referenced elsewheremay get garbage collected at any time, even before it’s done.For reliable “fire-and-forget” background tasks, gather them ina collection:
background_tasks=set()foriinrange(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)
Added in version 3.7.
Changed in version 3.8:Added thename parameter.
Changed in version 3.11:Added thecontext parameter.
Task Cancellation¶
Tasks can easily and safely be cancelled.When a task is cancelled,asyncio.CancelledError
will be raisedin the task at the next opportunity.
It is recommended that coroutines usetry/finally
blocks to robustlyperform clean-up logic. In caseasyncio.CancelledError
is explicitly caught, it should generally be propagated whenclean-up is complete.asyncio.CancelledError
directly subclassesBaseException
so most code will not need to be aware of it.
The asyncio components that enable structured concurrency, likeasyncio.TaskGroup
andasyncio.timeout()
,are implemented using cancellation internally and might misbehave ifa coroutine swallowsasyncio.CancelledError
. Similarly, user codeshould not generally calluncancel
.However, in cases when suppressingasyncio.CancelledError
istruly desired, it is necessary to also calluncancel()
to completelyremove the cancellation state.
Task Groups¶
Task groups combine a task creation API with a convenientand reliable way to wait for all tasks in the group to finish.
- classasyncio.TaskGroup¶
Anasynchronous context managerholding a group of tasks.Tasks can be added to the group using
create_task()
.All tasks are awaited when the context manager exits.Added in version 3.11.
- create_task(coro,*,name=None,context=None)¶
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 givencoro
.Changed in version 3.13:Close the given coroutine if the task group is not active.
Example:
asyncdefmain():asyncwithasyncio.TaskGroup()astg:task1=tg.create_task(some_coro(...))task2=tg.create_task(another_coro(...))print(f"Both tasks have completed now:{task1.result()},{task2.result()}")
Theasyncwith
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 passingtg
into one of the coroutinesand callingtg.create_task()
in that coroutine).Once the last task has finished and theasyncwith
block is exited,no new tasks may be added to the group.
The first time any of the tasks belonging to the group failswith an exception other thanasyncio.CancelledError
,the remaining tasks in the group are cancelled.No further tasks can then be added to the group.At this point, if the body of theasyncwith
statement is still active(i.e.,__aexit__()
hasn’t been called yet),the task directly containing theasyncwith
statement is also cancelled.The resultingasyncio.CancelledError
will interrupt anawait
,but it will not bubble out of the containingasyncwith
statement.
Once all tasks have finished, if any tasks have failedwith an exception other thanasyncio.CancelledError
,those exceptions are combined in anExceptionGroup
orBaseExceptionGroup
(as appropriate; see their documentation)which is then raised.
Two base exceptions are treated specially:If any task fails withKeyboardInterrupt
orSystemExit
,the task group still cancels the remaining tasks and waits for them,but then the initialKeyboardInterrupt
orSystemExit
is re-raised instead ofExceptionGroup
orBaseExceptionGroup
.
If the body of theasyncwith
statement exits with an exception(so__aexit__()
is called with an exception set),this is treated the same as if one of the tasks failed:the remaining tasks are cancelled and then waited for,and non-cancellation exceptions are grouped into anexception group and raised.The exception passed into__aexit__()
,unless it isasyncio.CancelledError
,is also included in the exception group.The same special case is made forKeyboardInterrupt
andSystemExit
as in the previous paragraph.
Task groups are careful not to mix up the internal cancellation used to“wake up” their__aexit__()
with cancellation requestsfor the task in which they are running made by other parties.In particular, when one task group is syntactically nested in another,and both experience an exception in one of their child tasks simultaneously,the inner task group will process its exceptions, and then the outer task groupwill receive another cancellation and process its own exceptions.
In the case where a task group is cancelled externally and also mustraise anExceptionGroup
, it will call the parent task’scancel()
method. This ensures that aasyncio.CancelledError
will be raised at the nextawait
, so the cancellation is not lost.
Task groups preserve the cancellation countreported byasyncio.Task.cancelling()
.
Changed in version 3.13:Improved handling of simultaneous internal and external cancellationsand correct preservation of cancellation counts.
Terminating a Task Group¶
While terminating a task group is not natively supported by the standardlibrary, termination can be achieved by adding an exception-raising taskto the task group and ignoring the raised exception:
importasynciofromasyncioimportTaskGroupclassTerminateTaskGroup(Exception):"""Exception raised to terminate a task group."""asyncdefforce_terminate_task_group():"""Used to force termination of a task group."""raiseTerminateTaskGroup()asyncdefjob(task_id,sleep_time):print(f'Task{task_id}: start')awaitasyncio.sleep(sleep_time)print(f'Task{task_id}: done')asyncdefmain():try:asyncwithTaskGroup()asgroup:# spawn some tasksgroup.create_task(job(1,0.5))group.create_task(job(2,1.5))# sleep for 1 secondawaitasyncio.sleep(1)# add an exception-raising task to force the group to terminategroup.create_task(force_terminate_task_group())except*TerminateTaskGroup:passasyncio.run(main())
Expected output:
Task 1: startTask 2: startTask 1: done
Sleeping¶
- asyncasyncio.sleep(delay,result=None)¶
Block fordelay seconds.
Ifresult is provided, it is returned to the callerwhen the coroutine completes.
sleep()
always suspends the current task, allowing other tasksto run.Setting the delay to 0 provides an optimized path to allow othertasks to run. This can be used by long-running functions to avoidblocking the event loop for the full duration of the function call.
Example of coroutine displaying the current date every secondfor 5 seconds:
importasyncioimportdatetimeasyncdefdisplay_date():loop=asyncio.get_running_loop()end_time=loop.time()+5.0whileTrue:print(datetime.datetime.now())if(loop.time()+1.0)>=end_time:breakawaitasyncio.sleep(1)asyncio.run(display_date())
Changed in version 3.10:Removed theloop parameter.
Changed in version 3.13:Raises
ValueError
ifdelay isnan
.
Running Tasks Concurrently¶
- awaitableasyncio.gather(*aws,return_exceptions=False)¶
Runawaitable objects in theawssequenceconcurrently.
If any awaitable inaws is a coroutine, it is automaticallyscheduled as a Task.
If all awaitables are completed successfully, the result is anaggregate list of returned values. The order of result valuescorresponds to the order of awaitables inaws.
Ifreturn_exceptions is
False
(default), the firstraised exception is immediately propagated to the task thatawaits ongather()
. Other awaitables in theaws sequencewon’t be cancelled and will continue to run.Ifreturn_exceptions is
True
, exceptions are treated thesame as successful results, and aggregated in the result list.If
gather()
iscancelled, all submitted awaitables(that have not completed yet) are alsocancelled.If any Task or Future from theaws sequence iscancelled, it istreated as if it raised
CancelledError
– thegather()
call isnot cancelled in this case. This is to prevent thecancellation of one submitted Task/Future to cause otherTasks/Futures to be cancelled.Note
A new alternative to create and run tasks concurrently andwait for their completion is
asyncio.TaskGroup
.TaskGroupprovides stronger safety guarantees thangather for scheduling a nesting of subtasks:if a task (or a subtask, a task scheduled by a task)raises an exception,TaskGroup will, whilegather will not,cancel the remaining scheduled tasks).Example:
importasyncioasyncdeffactorial(name,number):f=1foriinrange(2,number+1):print(f"Task{name}: Compute factorial({number}), currently i={i}...")awaitasyncio.sleep(1)f*=iprint(f"Task{name}: factorial({number}) ={f}")returnfasyncdefmain():# Schedule three calls *concurrently*:L=awaitasyncio.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]
Note
Ifreturn_exceptions is false, cancelling gather() after ithas been marked done won’t cancel any submitted awaitables.For instance, gather can be marked done after propagating anexception to the caller, therefore, calling
gather.cancel()
after catching an exception (raised by one of the awaitables) fromgather won’t cancel any other awaitables.Changed in version 3.7:If thegather itself is cancelled, the cancellation ispropagated regardless ofreturn_exceptions.
Changed in version 3.10:Removed theloop parameter.
Deprecated since version 3.10:Deprecation warning is emitted if no positional arguments are providedor not all positional arguments are Future-like objectsand there is no running event loop.
Eager Task Factory¶
- asyncio.eager_task_factory(loop,coro,*,name=None,context=None)¶
A task factory for eager task execution.
When using this factory (via
loop.set_task_factory(asyncio.eager_task_factory)
),coroutines begin execution synchronously duringTask
construction.Tasks are only scheduled on the event loop if they block.This can be a performance improvement as the overhead of loop schedulingis avoided for coroutines that complete synchronously.A common example where this is beneficial is coroutines which employcaching or memoization to avoid actual I/O when possible.
Note
Immediate execution of the coroutine is a semantic change.If the coroutine returns or raises, the task is never scheduledto the event loop. If the coroutine execution blocks, the task isscheduled to the event loop. This change may introduce behaviorchanges to existing applications. For example,the application’s task execution order is likely to change.
Added in version 3.12.
- asyncio.create_eager_task_factory(custom_task_constructor)¶
Create an eager task factory, similar to
eager_task_factory()
,using the providedcustom_task_constructor when creating a new task insteadof the defaultTask
.custom_task_constructor must be acallable with the signature matchingthe signature of
Task.__init__
.The callable must return aasyncio.Task
-compatible object.This function returns acallable intended to be used as a task factory of anevent loop via
loop.set_task_factory(factory)
).Added in version 3.12.
Shielding From Cancellation¶
- awaitableasyncio.shield(aw)¶
Protect anawaitable objectfrom being
cancelled
.Ifaw is a coroutine it is automatically scheduled as a Task.
The statement:
task=asyncio.create_task(something())res=awaitshield(task)
is equivalent to:
res=awaitsomething()
except that if the coroutine containing it is cancelled, theTask running in
something()
is not cancelled. From the pointof view ofsomething()
, the cancellation did not happen.Although its caller is still cancelled, so the “await” expressionstill raises aCancelledError
.If
something()
is cancelled by other means (i.e. from withinitself) that would also cancelshield()
.If it is desired to completely ignore cancellation (not recommended)the
shield()
function should be combined with a try/exceptclause, as follows:task=asyncio.create_task(something())try:res=awaitshield(task)exceptCancelledError:res=None
Important
Save a reference to tasks passed to this function, to avoida task disappearing mid-execution. The event loop only keepsweak references to tasks. A task that isn’t referenced elsewheremay get garbage collected at any time, even before it’s done.
Changed in version 3.10:Removed theloop parameter.
Deprecated since version 3.10:Deprecation warning is emitted ifaw is not Future-like objectand there is no running event loop.
Timeouts¶
- asyncio.timeout(delay)¶
Return anasynchronous context managerthat can be used to limit the amount of time spent waiting onsomething.
delay can either be
None
, or a float/int number ofseconds to wait. Ifdelay isNone
, no time limit willbe applied; this can be useful if the delay is unknown whenthe context manager is created.In either case, the context manager can be rescheduled aftercreation using
Timeout.reschedule()
.Example:
asyncdefmain():asyncwithasyncio.timeout(10):awaitlong_running_task()
If
long_running_task
takes more than 10 seconds to complete,the context manager will cancel the current task and handlethe resultingasyncio.CancelledError
internally, transforming itinto aTimeoutError
which can be caught and handled.Note
The
asyncio.timeout()
context manager is what transformstheasyncio.CancelledError
into aTimeoutError
,which means theTimeoutError
can only be caughtoutside of the context manager.Example of catching
TimeoutError
:asyncdefmain():try:asyncwithasyncio.timeout(10):awaitlong_running_task()exceptTimeoutError:print("The long operation timed out, but we've handled it.")print("This statement will run regardless.")
The context manager produced by
asyncio.timeout()
can berescheduled to a different deadline and inspected.- classasyncio.Timeout(when)¶
Anasynchronous context managerfor cancelling overdue coroutines.
when
should be an absolute time at which the context should time out,as measured by the event loop’s clock:If
when
isNone
, the timeout will never trigger.If
when<loop.time()
, the timeout will trigger on the nextiteration of the event loop.
Example:
asyncdefmain():try:# We do not know the timeout when starting, so we pass ``None``.asyncwithasyncio.timeout(None)ascm:# We know the timeout now, so we reschedule it.new_deadline=get_running_loop().time()+10cm.reschedule(new_deadline)awaitlong_running_task()exceptTimeoutError:passifcm.expired():print("Looks like we haven't finished on time.")
Timeout context managers can be safely nested.
Added in version 3.11.
- asyncio.timeout_at(when)¶
Similar to
asyncio.timeout()
, exceptwhen is the absolute timeto stop waiting, orNone
.Example:
asyncdefmain():loop=get_running_loop()deadline=loop.time()+20try:asyncwithasyncio.timeout_at(deadline):awaitlong_running_task()exceptTimeoutError:print("The long operation timed out, but we've handled it.")print("This statement will run regardless.")
Added in version 3.11.
- asyncasyncio.wait_for(aw,timeout)¶
Wait for theawawaitableto complete with a timeout.
Ifaw is a coroutine it is automatically scheduled as a Task.
timeout can either be
None
or a float or int number of secondsto wait for. Iftimeout isNone
, block until the futurecompletes.If a timeout occurs, it cancels the task and raises
TimeoutError
.To avoid the task
cancellation
,wrap it inshield()
.The function will wait until the future is actually cancelled,so the total wait time may exceed thetimeout. If an exceptionhappens during cancellation, it is propagated.
If the wait is cancelled, the futureaw is also cancelled.
Example:
asyncdefeternity():# Sleep for one hourawaitasyncio.sleep(3600)print('yay!')asyncdefmain():# Wait for at most 1 secondtry:awaitasyncio.wait_for(eternity(),timeout=1.0)exceptTimeoutError:print('timeout!')asyncio.run(main())# Expected output:## timeout!
Changed in version 3.7:Whenaw is cancelled due to a timeout,
wait_for
waitsforaw to be cancelled. Previously, it raisedTimeoutError
immediately.Changed in version 3.10:Removed theloop parameter.
Changed in version 3.11:Raises
TimeoutError
instead ofasyncio.TimeoutError
.
Waiting Primitives¶
- asyncasyncio.wait(aws,*,timeout=None,return_when=ALL_COMPLETED)¶
Run
Future
andTask
instances in theawsiterable concurrently and block until the condition specifiedbyreturn_when.Theaws iterable must not be empty.
Returns two sets of Tasks/Futures:
(done,pending)
.Usage:
done,pending=awaitasyncio.wait(aws)
timeout (a float or int), if specified, can be used to controlthe maximum number of seconds to wait before returning.
Note that this function does not raise
TimeoutError
.Futures or Tasks that aren’t done when the timeout occurs are simplyreturned in the second set.return_when indicates when this function should return. It mustbe one of the following constants:
Constant
Description
- asyncio.FIRST_COMPLETED¶
The function will return when any future finishes or is cancelled.
- asyncio.FIRST_EXCEPTION¶
The function will return when any future finishes by raising anexception. If no future raises an exceptionthen it is equivalent to
ALL_COMPLETED
.- asyncio.ALL_COMPLETED¶
The function will return when all futures finish or are cancelled.
Unlike
wait_for()
,wait()
does not cancel thefutures when a timeout occurs.Changed in version 3.10:Removed theloop parameter.
Changed in version 3.11:Passing coroutine objects to
wait()
directly is forbidden.Changed in version 3.12:Added support for generators yielding tasks.
- asyncio.as_completed(aws,*,timeout=None)¶
Runawaitable objects in theaws iterableconcurrently. The returned object can be iterated to obtain the resultsof the awaitables as they finish.
The object returned by
as_completed()
can be iterated as anasynchronous iterator or a plainiterator. When asynchronousiteration is used, the originally-supplied awaitables are yielded if theyare tasks or futures. This makes it easy to correlate previously-scheduledtasks with their results. Example:ipv4_connect=create_task(open_connection("127.0.0.1",80))ipv6_connect=create_task(open_connection("::1",80))tasks=[ipv4_connect,ipv6_connect]asyncforearliest_connectinas_completed(tasks):# earliest_connect is done. The result can be obtained by# awaiting it or calling earliest_connect.result()reader,writer=awaitearliest_connectifearliest_connectisipv6_connect:print("IPv6 connection established.")else:print("IPv4 connection established.")
During asynchronous iteration, implicitly-created tasks will be yielded forsupplied awaitables that aren’t tasks or futures.
When used as a plain iterator, each iteration yields a new coroutine thatreturns the result or raises the exception of the next completed awaitable.This pattern is compatible with Python versions older than 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]fornext_connectinas_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=awaitnext_connect
A
TimeoutError
is raised if the timeout occurs before all awaitablesare done. This is raised by theasyncfor
loop during asynchronousiteration or by the coroutines yielded during plain iteration.Changed in version 3.10:Removed theloop parameter.
Deprecated since version 3.10:Deprecation warning is emitted if not all awaitable objects in theawsiterable are Future-like objects and there is no running event loop.
Changed in version 3.12:Added support for generators yielding tasks.
Changed in version 3.13:The result can now be used as either anasynchronous iteratoror as a plainiterator (previously it was only a plain iterator).
Running in Threads¶
- asyncasyncio.to_thread(func,/,*args,**kwargs)¶
Asynchronously run functionfunc in a separate thread.
Any *args and **kwargs supplied for this function are directly passedtofunc. Also, the current
contextvars.Context
is propagated,allowing context variables from the event loop thread to be accessed in theseparate thread.Return a coroutine that can be awaited to get the eventual result offunc.
This coroutine function is primarily intended to be used for executingIO-bound functions/methods that would otherwise block the event loop ifthey were run in the main thread. For example:
defblocking_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')}")asyncdefmain():print(f"started main at{time.strftime('%X')}")awaitasyncio.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
Directly calling
blocking_io()
in any coroutine would block the event loopfor its duration, resulting in an additional 1 second of run time. Instead,by usingasyncio.to_thread()
, we can run it in a separate thread withoutblocking the event loop.Note
Due to theGIL,
asyncio.to_thread()
can typically only be usedto make IO-bound functions non-blocking. However, for extension modulesthat release the GIL or alternative Python implementations that don’thave one,asyncio.to_thread()
can also be used for CPU-bound functions.Added in version 3.9.
Scheduling From Other Threads¶
- asyncio.run_coroutine_threadsafe(coro,loop)¶
Submit a coroutine to the given event loop. Thread-safe.
Return a
concurrent.futures.Future
to wait for the resultfrom another OS thread.This function is meant to be called from a different OS threadthan the one where the event loop is running. Example:
# Create a coroutinecoro=asyncio.sleep(1,result=3)# Submit the coroutine to a given loopfuture=asyncio.run_coroutine_threadsafe(coro,loop)# Wait for the result with an optional timeout argumentassertfuture.result(timeout)==3
If an exception is raised in the coroutine, the returned Futurewill be notified. It can also be used to cancel the task inthe event loop:
try:result=future.result(timeout)exceptTimeoutError:print('The coroutine took too long, cancelling the task...')future.cancel()exceptExceptionasexc:print(f'The coroutine raised an exception:{exc!r}')else:print(f'The coroutine returned:{result!r}')
See theconcurrency and multithreadingsection of the documentation.
Unlike other asyncio functions this function requires theloopargument to be passed explicitly.
Added in version 3.5.1.
Introspection¶
- asyncio.current_task(loop=None)¶
Return the currently running
Task
instance, orNone
ifno task is running.Ifloop is
None
get_running_loop()
is used to getthe current loop.Added in version 3.7.
- asyncio.all_tasks(loop=None)¶
Return a set of not yet finished
Task
objects run bythe loop.Ifloop is
None
,get_running_loop()
is used for gettingcurrent loop.Added in version 3.7.
- asyncio.iscoroutine(obj)¶
Return
True
ifobj is a coroutine object.Added in version 3.4.
Task Object¶
- classasyncio.Task(coro,*,loop=None,name=None,context=None,eager_start=False)¶
A
Future-like
object that runs a Pythoncoroutine. Not thread-safe.Tasks are used to run coroutines in event loops.If a coroutine awaits on a Future, the Task suspendsthe execution of the coroutine and waits for the completionof the Future. When the Future isdone, the execution ofthe wrapped coroutine resumes.
Event loops use cooperative scheduling: an event loop runsone Task at a time. While a Task awaits for the completion of aFuture, the event loop runs other Tasks, callbacks, or performsIO operations.
Use the high-level
asyncio.create_task()
function to createTasks, or the low-levelloop.create_task()
orensure_future()
functions. Manual instantiation of Tasksis discouraged.To cancel a running Task use the
cancel()
method. Calling itwill cause the Task to throw aCancelledError
exception intothe wrapped coroutine. If a coroutine is awaiting on a Futureobject during cancellation, the Future object will be cancelled.cancelled()
can be used to check if the Task was cancelled.The method returnsTrue
if the wrapped coroutine did notsuppress theCancelledError
exception and was actuallycancelled.asyncio.Task
inherits fromFuture
all of itsAPIs exceptFuture.set_result()
andFuture.set_exception()
.An optional keyword-onlycontext argument allows specifying acustom
contextvars.Context
for thecoro to run in.If nocontext is provided, the Task copies the current contextand later runs its coroutine in the copied context.An optional keyword-onlyeager_start argument allows eagerly startingthe execution of the
asyncio.Task
at task creation time.If set toTrue
and the event loop is running, the task will startexecuting the coroutine immediately, until the first time the coroutineblocks. If the coroutine returns or raises without blocking, the taskwill be finished eagerly and will skip scheduling to the event loop.Changed in version 3.7:Added support for the
contextvars
module.Changed in version 3.8:Added thename parameter.
Deprecated since version 3.10:Deprecation warning is emitted ifloop is not specifiedand there is no running event loop.
Changed in version 3.11:Added thecontext parameter.
Changed in version 3.12:Added theeager_start parameter.
- done()¶
Return
True
if the Task isdone.A Task isdone when the wrapped coroutine either returneda value, raised an exception, or the Task was cancelled.
- result()¶
Return the result of the Task.
If the Task isdone, the result of the wrapped coroutineis returned (or if the coroutine raised an exception, thatexception is re-raised.)
If the Task has beencancelled, this method raisesa
CancelledError
exception.If the Task’s result isn’t yet available, this method raisesan
InvalidStateError
exception.
- exception()¶
Return the exception of the Task.
If the wrapped coroutine raised an exception that exceptionis returned. If the wrapped coroutine returned normallythis method returns
None
.If the Task has beencancelled, this method raises a
CancelledError
exception.If the Task isn’tdone yet, this method raises an
InvalidStateError
exception.
- add_done_callback(callback,*,context=None)¶
Add a callback to be run when the Task isdone.
This method should only be used in low-level callback-based code.
See the documentation of
Future.add_done_callback()
for more details.
- remove_done_callback(callback)¶
Removecallback from the callbacks list.
This method should only be used in low-level callback-based code.
See the documentation of
Future.remove_done_callback()
for more details.
- get_stack(*,limit=None)¶
Return the list of stack frames for this Task.
If the wrapped coroutine is not done, this returns the stackwhere it is suspended. If the coroutine has completedsuccessfully or was cancelled, this returns an empty list.If the coroutine was terminated by an exception, this returnsthe list of traceback frames.
The frames are always ordered from oldest to newest.
Only one stack frame is returned for a suspended coroutine.
The optionallimit argument sets the maximum number of framesto return; by default all available frames are returned.The ordering of the returned list differs depending on whethera stack or a traceback is returned: the newest frames of astack are returned, but the oldest frames of a traceback arereturned. (This matches the behavior of the traceback module.)
- print_stack(*,limit=None,file=None)¶
Print the stack or traceback for this Task.
This produces output similar to that of the traceback modulefor the frames retrieved by
get_stack()
.Thelimit argument is passed to
get_stack()
directly.Thefile argument is an I/O stream to which the outputis written; by default output is written to
sys.stdout
.
- get_coro()¶
Return the coroutine object wrapped by the
Task
.Note
This will return
None
for Tasks which have alreadycompleted eagerly. See theEager Task Factory.Added in version 3.8.
Changed in version 3.12:Newly added eager task execution means result may be
None
.
- get_context()¶
Return the
contextvars.Context
objectassociated with the task.Added in version 3.12.
- get_name()¶
Return the name of the Task.
If no name has been explicitly assigned to the Task, the defaultasyncio Task implementation generates a default name duringinstantiation.
Added in version 3.8.
- set_name(value)¶
Set the name of the Task.
Thevalue argument can be any object, which is thenconverted to a string.
In the default Task implementation, the name will be visiblein the
repr()
output of a task object.Added in version 3.8.
- cancel(msg=None)¶
Request the Task to be cancelled.
If the Task is alreadydone orcancelled, return
False
,otherwise, returnTrue
.The method arranges for a
CancelledError
exception to be throwninto the wrapped coroutine on the next cycle of the event loop.The coroutine then has a chance to clean up or even deny therequest by suppressing the exception with a
try
……exceptCancelledError
…finally
block.Therefore, unlikeFuture.cancel()
,Task.cancel()
doesnot guarantee that the Task will be cancelled, althoughsuppressing cancellation completely is not common and is activelydiscouraged. Should the coroutine nevertheless decide to suppressthe cancellation, it needs to callTask.uncancel()
in additionto catching the exception.Changed in version 3.9:Added themsg parameter.
Changed in version 3.11:The
msg
parameter is propagated from cancelled task to its awaiter.The following example illustrates how coroutines can interceptthe cancellation request:
asyncdefcancel_me():print('cancel_me(): before sleep')try:# Wait for 1 hourawaitasyncio.sleep(3600)exceptasyncio.CancelledError:print('cancel_me(): cancel sleep')raisefinally:print('cancel_me(): after sleep')asyncdefmain():# Create a "cancel_me" Tasktask=asyncio.create_task(cancel_me())# Wait for 1 secondawaitasyncio.sleep(1)task.cancel()try:awaittaskexceptasyncio.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()¶
Return
True
if the Task iscancelled.The Task iscancelled when the cancellation was requested with
cancel()
and the wrapped coroutine propagated theCancelledError
exception thrown into it.
- uncancel()¶
Decrement the count of cancellation requests to this Task.
Returns the remaining number of cancellation requests.
Note that once execution of a cancelled task completed, furthercalls to
uncancel()
are ineffective.Added in version 3.11.
This method is used by asyncio’s internals and isn’t expected to beused by end-user code. In particular, if a Task gets successfullyuncancelled, this allows for elements of structured concurrency likeTask Groups and
asyncio.timeout()
to continue running,isolating cancellation to the respective structured block.For example:asyncdefmake_request_with_timeout():try:asyncwithasyncio.timeout(1):# Structured block affected by the timeout:awaitmake_request()awaitmake_another_request()exceptTimeoutError:log("There was a timeout")# Outer code not affected by the timeout:awaitunrelated_code()
While the block with
make_request()
andmake_another_request()
might get cancelled due to the timeout,unrelated_code()
shouldcontinue running even in case of the timeout. This is implementedwithuncancel()
.TaskGroup
context managers useuncancel()
in a similar fashion.If end-user code is, for some reason, suppressing cancellation bycatching
CancelledError
, it needs to call this method to removethe cancellation state.When this method decrements the cancellation count to zero,the method checks if a previous
cancel()
call had arrangedforCancelledError
to be thrown into the task.If it hasn’t been thrown yet, that arrangement will berescinded (by resetting the internal_must_cancel
flag).
Changed in version 3.13:Changed to rescind pending cancellation requests upon reaching zero.
- cancelling()¶
Return the number of pending cancellation requests to this Task, i.e.,the number of calls to
cancel()
less the number ofuncancel()
calls.Note that if this number is greater than zero but the Task isstill executing,
cancelled()
will still returnFalse
.This is because this number can be lowered by callinguncancel()
,which can lead to the task not being cancelled after all if thecancellation requests go down to zero.This method is used by asyncio’s internals and isn’t expected to beused by end-user code. See
uncancel()
for more details.Added in version 3.11.