@@ -386,16 +386,16 @@ async def open_loop(queue_len=None):
386
386
387
387
Exiting the context manager will attempt to do an orderly shutdown
388
388
of the tasks it contains, analogously to :func:`asyncio.run`.
389
- asyncio-flavored tasks are cancelled and awaited first, then
390
- Trio-flavored tasks that were started using
391
- :meth:`~BaseTrioEventLoop.trio_as_future` or
392
- :meth:`~BaseTrioEventLoop.run_trio_task`. All
389
+ Both asyncio-flavored tasks and Trio-flavored tasks (the latter
390
+ started using :meth:`~BaseTrioEventLoop.trio_as_future`,
391
+ :meth:`~BaseTrioEventLoop.run_trio_task`, :func:`trio_as_aio`,
392
+ etc) are cancelled simultaneously, and the loop waits for them to
393
+ exit in response to this cancellation before proceeding. All
393
394
:meth:`~asyncio.loop.call_soon` callbacks that are submitted
394
- before exiting the context manager will run before starting
395
- this shutdown sequence, and all callbacks that are submitted
396
- before the last task exits will run before the loop closes.
397
- The exact point at which the loop stops running callbacks is
398
- not specified.
395
+ before exiting the context manager will run before starting this
396
+ shutdown sequence, and all callbacks that are submitted before the
397
+ last task exits will run before the loop closes. The exact point
398
+ at which the loop stops running callbacks is not specified.
399
399
400
400
.. warning:: As with :func:`asyncio.run`, asyncio-flavored tasks
401
401
that are started *after* exiting the context manager (such as by
@@ -447,27 +447,22 @@ async def wait_for_sync():
447
447
await loop .wait_stopped ()
448
448
sync_nursery .cancel_scope .cancel ()
449
449
450
- # Cancel and wait on all currently-running asyncio tasks.
450
+ # Cancel and wait on all currently-running tasks.
451
+ # Exiting the tasks_nursery will wait for the Trio tasks
452
+ # automatically; we mix in the asyncio tasks by scheduling
453
+ # a call to run_aio_future() for each one. It's important
454
+ # not to wait on one kind of task before the other, so that
455
+ # we support Trio tasks that need to run some asyncio
456
+ # code during teardown as well as the opposite.
451
457
# Like asyncio.run(), we don't bother cancelling and waiting
452
- # on any additional tasks that these tasks start as they
458
+ # on any additional asyncio tasks that these tasks start as they
453
459
# unwind.
454
460
if sys .version_info >= (3 , 7 ):
455
461
aio_tasks = asyncio .all_tasks (loop )
456
462
else :
457
463
aio_tasks = {t for t in asyncio .Task .all_tasks (loop ) if not t .done ()}
458
- if aio_tasks :
459
- # Start one Trio task to wait for each still-running
460
- # asyncio task. This provides better exception
461
- # propagation than using asyncio.gather().
462
- async with trio .open_nursery () as aio_cancel_nursery :
463
- for task in aio_tasks :
464
- aio_cancel_nursery .start_soon (run_aio_future , task )
465
- aio_cancel_nursery .cancel_scope .cancel ()
466
-
467
- # If there are any trio_as_aio tasks still going after
468
- # the cancellation of asyncio tasks above, this will
469
- # cancel them, and exiting the tasks_nursery block
470
- # will wait for them to exit.
464
+ for task in aio_tasks :
465
+ tasks_nursery .start_soon (run_aio_future , task )
471
466
tasks_nursery .cancel_scope .cancel ()
472
467
finally :
473
468
try :
0 commit comments