Рубрики
Без рубрики

Выполнение задач одновременно

Автор оригинала: Doug Hellmann.

Задачи – один из основных способов взаимодействия с циклом событий. Задачи обертывают сопрограммы и отслеживают их выполнение. Задачи являются подклассами Future , поэтому другие сопрограммы могут их ждать, и каждая из них имеет результат, который можно получить после завершения задачи.

Запуск задачи

Чтобы запустить задачу, используйте create_task () для создания экземпляра Task . Результирующая задача будет выполняться как часть параллельных операций, управляемых циклом событий, пока цикл выполняется и сопрограмма не возвращается.

asyncio_create_task.py

import asyncio


async def task_func():
    print('in task_func')
    return 'the result'


async def main(loop):
    print('creating task')
    task  loop.create_task(task_func())
    print('waiting for {!r}'.format(task))
    return_value  await task
    print('task completed {!r}'.format(task))
    print('return value: {!r}'.format(return_value))


event_loop  asyncio.get_event_loop()
try:
    event_loop.run_until_complete(main(event_loop))
finally:
    event_loop.close()

В этом примере перед завершением работы функции main () ожидается, пока задача не вернет результат.

$ python3 asyncio_create_task.py

creating task
waiting for >
in task_func
task completed >
return value: 'the result'

Отмена задачи

Сохраняя объект Task , возвращенный из create_task () , можно отменить операцию задачи до ее завершения.

asyncio_cancel_task.py

import asyncio


async def task_func():
    print('in task_func')
    return 'the result'


async def main(loop):
    print('creating task')
    task  loop.create_task(task_func())

    print('canceling task')
    task.cancel()

    print('canceled task {!r}'.format(task))
    try:
        await task
    except asyncio.CancelledError:
        print('caught error from canceled task')
    else:
        print('task result: {!r}'.format(task.result()))


event_loop  asyncio.get_event_loop()
try:
    event_loop.run_until_complete(main(event_loop))
finally:
    event_loop.close()

В этом примере создается и затем отменяется задача перед запуском цикла событий. Результатом является исключение CancelledError из run_until_complete () .

$ python3 asyncio_cancel_task.py

creating task
canceling task
canceled task >
caught error from canceled task

Если задача отменяется во время ожидания другой параллельной операции, задача уведомляется о ее отмене, вызывая исключение CancelledError в точке, где она ожидает.

asyncio_cancel_task2.py

import asyncio


async def task_func():
    print('in task_func, sleeping')
    try:
        await asyncio.sleep(1)
    except asyncio.CancelledError:
        print('task_func was canceled')
        raise
    return 'the result'


def task_canceller(t):
    print('in task_canceller')
    t.cancel()
    print('canceled the task')


async def main(loop):
    print('creating task')
    task  loop.create_task(task_func())
    loop.call_soon(task_canceller, task)
    try:
        await task
    except asyncio.CancelledError:
        print('main() also sees task as canceled')


event_loop  asyncio.get_event_loop()
try:
    event_loop.run_until_complete(main(event_loop))
finally:
    event_loop.close()

Перехват исключения дает возможность при необходимости очистить уже выполненную работу.

$ python3 asyncio_cancel_task2.py

creating task
in task_func, sleeping
in task_canceller
canceled the task
task_func was canceled
main() also sees task as canceled

Создание задач из сопрограмм

Функция sure_future () возвращает Task , привязанную к выполнению сопрограммы. Затем этот экземпляр Task можно передать другому коду, который может ждать его, не зная, как была создана или вызвана исходная сопрограмма.

asyncio_ensure_future.py

import asyncio


async def wrapped():
    print('wrapped')
    return 'result'


async def inner(task):
    print('inner: starting')
    print('inner: waiting for {!r}'.format(task))
    result  await task
    print('inner: task returned {!r}'.format(result))


async def starter():
    print('starter: creating task')
    task  asyncio.ensure_future(wrapped())
    print('starter: waiting for inner')
    await inner(task)
    print('starter: inner returned')


event_loop  asyncio.get_event_loop()
try:
    print('entering event loop')
    result  event_loop.run_until_complete(starter())
finally:
    event_loop.close()

Обратите внимание, что сопрограмма, переданная в sure_future () , не запускается, пока что-то не использует await , чтобы разрешить ее выполнение.

$ python3 asyncio_ensure_future.py

entering event loop
starter: creating task
starter: waiting for inner
inner: starting
inner: waiting for >
wrapped
inner: task returned 'result'
starter: inner returned