Документация Python неофициальный перевод

asyncio-task.md

862 строк · 52.6 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.10/library/asyncio-task.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Корутины и задачи89В этом разделе представлены высокоуровневые API asyncio для работы с корутинами и задачами.1011- [Корутины](https://python-all.ru/3.10/library/asyncio-task.html#coroutines)12- [Ожидаемые объекты](https://python-all.ru/3.10/library/asyncio-task.html#awaitables)13- [Запуск asyncio-программы](https://python-all.ru/3.10/library/asyncio-task.html#running-an-asyncio-program)14- [Создание задач](https://python-all.ru/3.10/library/asyncio-task.html#creating-tasks)15- [Приостановка выполнения](https://python-all.ru/3.10/library/asyncio-task.html#sleeping)16- [Одновременное выполнение задач](https://python-all.ru/3.10/library/asyncio-task.html#running-tasks-concurrently)17- [Защита от отмены](https://python-all.ru/3.10/library/asyncio-task.html#shielding-from-cancellation)18- [Тайм-ауты](https://python-all.ru/3.10/library/asyncio-task.html#timeouts)19- [Примитивы ожидания](https://python-all.ru/3.10/library/asyncio-task.html#waiting-primitives)20- [Выполнение в потоках](https://python-all.ru/3.10/library/asyncio-task.html#running-in-threads)21- [Планирование из других потоков](https://python-all.ru/3.10/library/asyncio-task.html#scheduling-from-other-threads)22- [Интроспекция](https://python-all.ru/3.10/library/asyncio-task.html#introspection)23- [Объект задачи](https://python-all.ru/3.10/library/asyncio-task.html#task-object)24- [Корутины на основе генераторов](https://python-all.ru/3.10/library/asyncio-task.html#generator-based-coroutines)2526## [Корутины](https://python-all.ru/3.10/library/asyncio-task.html#id1)2728**Исходный код:** [Lib/asyncio/coroutines.py](https://python-all.ru/src/3.10/Lib/asyncio/coroutines.py)2930---3132[Корутины](https://python-all.ru/3.10/glossary.html#term-coroutine), объявленные с помощью синтаксиса async/await, являются предпочтительным способом написания приложений asyncio. Например, следующий фрагмент кода выводит «hello», ждёт 1 секунду, а затем выводит «world»:3334```python35>>> import asyncio3637>>> async def main():38...     print('hello')39...     await asyncio.sleep(1)40...     print('world')4142>>> asyncio.run(main())43hello44world45```4647Обратите внимание, что простой вызов корутины не запланирует её выполнение:4849```python50>>> main()51<coroutine object main at 0x1053bb7c8>52```5354Для фактического запуска корутины asyncio предоставляет три основных механизма:5556- Функция [`asyncio.run()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.run) для запуска точки входа верхнего уровня – функции «main()» (см. пример выше.)57- Ожидание корутины. Следующий фрагмент кода выведет «hello» после ожидания в 1 секунду, а затем выведет «world» после ожидания *ещё* 2 секунд:5859  ```python60  import asyncio61  import time6263  async def say_after(delay, what):64      await asyncio.sleep(delay)65      print(what)6667  async def main():68      print(f"started at {time.strftime('%X')}")6970      await say_after(1, 'hello')71      await say_after(2, 'world')7273      print(f"finished at {time.strftime('%X')}")7475  asyncio.run(main())76  ```7778  Ожидаемый вывод:7980  ```python81  started at 17:13:5282  hello83  world84  finished at 17:13:5585  ```86- Функция [`asyncio.create_task()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.create_task) для параллельного запуска корутин в качестве asyncio [`Tasks`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task).8788  Давайте изменим пример выше и запустим две `say_after` корутины *параллельно*:8990  ```python91  async def main():92      task1 = asyncio.create_task(93          say_after(1, 'hello'))9495      task2 = asyncio.create_task(96          say_after(2, 'world'))9798      print(f"started at {time.strftime('%X')}")99100      # Ожидать завершения обеих задач (должно занять101      # около 2 секунд).102      await task1103      await task2104105      print(f"finished at {time.strftime('%X')}")106  ```107108  Обратите внимание, что ожидаемый вывод теперь показывает, что фрагмент выполняется на 1 секунду быстрее, чем раньше:109110  ```python111  started at 17:14:32112  hello113  world114  finished at 17:14:34115  ```116117## [Ожидаемые объекты](https://python-all.ru/3.10/library/asyncio-task.html#id2)118119Говорят, что объект является **ожидаемым** объектом, если его можно использовать в выражении [`await`](https://python-all.ru/3.10/reference/expressions.html#await). Многие API asyncio предназначены для принятия ожидаемых объектов.120121Существует три основных типа *ожидаемых* объектов: **корутины**, **задачи** и **future**.122123Корутины124125Корутины Python являются *ожидаемыми объектами*, а значит, их можно ожидать из других корутин:126127```python128import asyncio129130async def nested():131    return 42132133async def main():134    # Если просто вызвать "nested()", ничего не произойдет.135    # Создается объект корутины, но он не ожидается,136    # поэтому он *вообще не выполнится*.137    nested()138139    # Давайте поступим иначе и теперь ожидаем его:140    print(await nested())  # выведет "42".141142asyncio.run(main())143```144145> **Важно**146>147> В данной документации термин «корутина» может использоваться для двух тесно связанных понятий:148>149> - *корутинная функция*: функция [`async def`](https://python-all.ru/3.10/reference/compound_stmts.html#async-def);150> - *объект корутины*: объект, возвращаемый при вызове *корутинной функции*.151152asyncio также поддерживает устаревшие [корутины на основе генераторов](https://python-all.ru/3.10/library/asyncio-task.html#asyncio-generator-based-coro).153154Задачи155156*Задачи* используются для планирования корутин *параллельно*.157158Когда корутина обёрнута в *задачу* с помощью таких функций, как [`asyncio.create_task()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.create_task), корутина автоматически планируется к скорому выполнению:159160```python161import asyncio162163async def nested():164    return 42165166async def main():167    # Запланировать выполнение nested() вскоре конкурентно168    # с "main()".169    task = asyncio.create_task(nested())170171    # "задача" теперь можно использовать для отмены "nested()" или172    # можно просто применить await, чтобы дождаться завершения:173    await task174175asyncio.run(main())176```177178Future179180[`Future`](https://python-all.ru/3.10/library/asyncio-future.html#asyncio.Future) – это специальный **низкоуровневый** ожидаемый объект, который представляет **конечный результат** асинхронной операции.181182Когда объект Future *ожидается*, это означает, что корутина будет ожидать, пока Future не будет разрешён в каком-то другом месте.183184Объекты Future в asyncio необходимы для того, чтобы код, основанный на колбэках, мог использоваться с async/await.185186Обычно **нет необходимости** создавать объекты Future в коде уровня приложения.187188Объекты Future, иногда предоставляемые библиотеками и некоторыми API asyncio, можно ожидать (await):189190```python191async def main():192    await function_that_returns_a_future_object()193194    # это также допустимо:195    await asyncio.gather(196        function_that_returns_a_future_object(),197        some_python_coroutine()198    )199```200201Хороший пример низкоуровневой функции, возвращающей объект Future – [`loop.run_in_executor()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.run_in_executor).202203## [Запуск программы asyncio](https://python-all.ru/3.10/library/asyncio-task.html#id3)204205#### `asyncio.run(coro, *, debug=False)`206207Выполняет [корутину](https://python-all.ru/3.10/glossary.html#term-coroutine) *coro* и возвращает результат.208209Эта функция выполняет переданную корутину, беря на себя управление циклом событий asyncio, *завершение асинхронных генераторов* и закрытие пула потоков.210211Эту функцию нельзя вызывать, когда в том же потоке выполняется другой цикл событий asyncio.212213Если *debug* равно `True`, цикл событий будет запущен в режиме отладки.214215Эта функция всегда создаёт новый цикл событий и закрывает его в конце. Её следует использовать в качестве главной точки входа для программ asyncio, и в идеале она должна вызываться только один раз.216217Пример:218219```python220async def main():221    await asyncio.sleep(1)222    print('hello')223224asyncio.run(main())225```226227Добавлено в версии 3.7.228229Изменено в версии 3.9: Обновлено для использования [`loop.shutdown_default_executor()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.shutdown_default_executor).230231> **Примечание**232>233> Исходный код `asyncio.run()` можно найти в\\n[Lib/asyncio/runners.py](https://python-all.ru/src/3.10/Lib/asyncio/runners.py).234235## [Создание задач](https://python-all.ru/3.10/library/asyncio-task.html#id4)236237**Исходный код:** [Lib/asyncio/tasks.py](https://python-all.ru/src/3.10/Lib/asyncio/tasks.py)238239---240241#### `asyncio.create_task(coro, *, name=None)`242243Wrap the *coro* [coroutine](https://python-all.ru/3.10/library/asyncio-task.html#coroutine) into a [`Task`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task) and schedule its execution. Return the Task object.244245Если *name* не равен `None`, он устанавливается как имя задачи с помощью [`Task.set_name()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task.set_name).246247Задача выполняется в цикле, возвращаемом [`get_running_loop()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.get_running_loop); [`RuntimeError`](https://python-all.ru/3.10/library/exceptions.html#RuntimeError) возбуждается, если в текущем потоке нет запущенного цикла.248249> **Важно**250>251> Сохраняйте ссылку на результат этой функции, чтобы задача не исчезла во время выполнения. Цикл событий хранит только слабые ссылки на задачи. Задача, на которую нет других ссылок, может быть собрана сборщиком мусора в любой момент, даже до завершения. Для надёжных фоновых задач «запустил и забыл» собирайте их в коллекцию:252>253> ```python254> background_tasks = set()255>256> for i in range(10):257>     task = asyncio.create_task(some_coro(param=i))258>259>     # Добавить задачу в множество. Это создаёт сильную ссылку.260>     background_tasks.add(task)261>262>     # Чтобы предотвратить постоянное хранение ссылок на завершённые задачи,263>     # нужно, чтобы каждая задача удаляла свою собственную ссылку из множества после264>     # завершения:265>     task.add_done_callback(background_tasks.discard)266> ```267268Добавлено в версии 3.7.269270Изменено в версии 3.8: Добавлен параметр *name*.271272## [Ожидание](https://python-all.ru/3.10/library/asyncio-task.html#id5)273274#### `coroutine asyncio.sleep(delay, result=None)`275276Приостанавливает выполнение на *delay* секунд.277278Если *result* указан, он возвращается вызывающей стороне после завершения корутины.279280`sleep()` всегда приостанавливает текущую задачу, позволяя выполняться другим задачам.281282Установка задержки в 0 обеспечивает оптимизированный путь, позволяющий выполняться другим задачам. Это может использоваться длительными функциями, чтобы избежать блокировки цикла событий на всё время вызова функции.283284Устарело с версии 3.8, удалено в версии 3.10: Параметр `loop`. Эта функция неявно получала\\nтекущий запущенный цикл, начиная с версии 3.7. См.\\n[раздел «Что нового в 3.10: удалённое»](https://python-all.ru/3.10/whatsnew/3.10.html#whatsnew310-removed)\\nдля получения дополнительной информации.285286Пример корутины, выводящей текущую дату каждую секунду в течение 5 секунд:287288```python289import asyncio290import datetime291292async def display_date():293    loop = asyncio.get_running_loop()294    end_time = loop.time() + 5.0295    while True:296        print(datetime.datetime.now())297        if (loop.time() + 1.0) >= end_time:298            break299        await asyncio.sleep(1)300301asyncio.run(display_date())302```303304Изменено в версии 3.10: Удалён параметр *loop*.305306## [Одновременный запуск задач](https://python-all.ru/3.10/library/asyncio-task.html#id6)307308#### `awaitable asyncio.gather(*aws, return_exceptions=False)`309310Выполняет [ожидаемые объекты](https://python-all.ru/3.10/library/asyncio-task.html#asyncio-awaitables) из последовательности *aws* *одновременно*.311312Если любой ожидаемый объект из *aws* является корутиной, он автоматически планируется как задача.313314Если все ожидаемые объекты завершены успешно, результатом является сводный список возвращённых значений. Порядок значений результата соответствует порядку ожидаемых объектов в *aws*.315316Если *return\_exceptions* равно `False` (по умолчанию), первое возбуждённое исключение немедленно распространяется на задачу, ожидающую `gather()`. Остальные ожидаемые объекты в последовательности *aws* **не будут отменены** и продолжат выполнение.317318Если *return\_exceptions* равно `True`, исключения обрабатываются так же, как успешные результаты, и объединяются в списке результатов.319320Если `gather()` *отменён*, все переданные ожидаемые объекты (которые ещё не завершились) также *отменяются*.321322Если любая задача или Future из последовательности *aws* *отменена*, это рассматривается так, как если бы она возбудила [`CancelledError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.CancelledError) – вызов `gather()` в этом случае **не** отменяется. Это сделано для предотвращения ситуации, когда отмена одной переданной задачи или Future приводит к отмене других задач или Future.323324Изменено в версии 3.10: Удалён параметр *loop*.325326Пример:327328```python329import asyncio330331async def factorial(name, number):332    f = 1333    for i in range(2, number + 1):334        print(f"Task {name}: Compute factorial({number}), currently i={i}...")335        await asyncio.sleep(1)336        f *= i337    print(f"Task {name}: factorial({number}) = {f}")338    return f339340async def main():341    # Запланировать три вызова *конкурентно*:342    L = await asyncio.gather(343        factorial("A", 2),344        factorial("B", 3),345        factorial("C", 4),346    )347    print(L)348349asyncio.run(main())350351# Ожидаемый вывод:352#353#     Задача A: вычисление factorial(2), сейчас i=2...354#     Задача B: вычисление factorial(3), сейчас i=2...355#     Задача C: вычисление factorial(4), сейчас i=2...356#     Задача A: factorial(2) = 2357#     Задача B: вычисление factorial(3), сейчас i=3...358#     Задача C: вычисление factorial(4), сейчас i=3...359#     Задача B: factorial(3) = 6360#     Задача C: вычисление factorial(4), сейчас i=4...361#     Задача C: factorial(4) = 24362#     [2, 6, 24]363```364365> **Примечание**366>367> Если *return\_exceptions* равно False, отмена gather() после того, как он был помечен как завершённый, не отменит ни один из переданных ожидаемых объектов. Например, gather может быть помечен как завершённый после распространения исключения вызывающему коду; следовательно, вызов `gather.cancel()` после перехвата исключения (возбуждённого одним из ожидаемых объектов) из gather не отменит другие ожидаемые объекты.368369Изменено в версии 3.7: Если сам *gather* отменён, отмена распространяется независимо от *return\_exceptions*.370371Изменено в версии 3.10: Удалён параметр *loop*.372373Устарело с версии 3.10: Предупреждение об устаревании выдается, если не предоставлены позиционные аргументы или не все позиционные аргументы являются объектами, подобными Future, и нет запущенного цикла событий.374375## [Защита от отмены](https://python-all.ru/3.10/library/asyncio-task.html#id7)376377#### `awaitable asyncio.shield(aw)`378379Защищает [ожидаемый объект](https://python-all.ru/3.10/library/asyncio-task.html#asyncio-awaitables) от [`cancelled`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task.cancel).380381Если *aw* является корутиной, она автоматически планируется как задача.382383Выражение:384385```python386task = asyncio.create_task(something())387res = await shield(task)388```389390эквивалентно:391392```python393res = await something()394```395396*За исключением* того, что если содержащая его корутина отменяется, задача, выполняющаяся в `something()`, не отменяется. С точки зрения `something()` отмена не произошла. Хотя её вызывающий код всё ещё отменён, поэтому выражение «await» по-прежнему возбуждает [`CancelledError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.CancelledError).397398Если `something()` отменяется другими средствами (т.е. изнутри самой себя), это также отменит `shield()`.399400Если требуется полностью игнорировать отмену (не рекомендуется), функцию `shield()` следует комбинировать с конструкцией try/except следующим образом:401402```python403task = asyncio.create_task(something())404try:405    res = await shield(task)406except CancelledError:407    res = None408```409410> **Важно**411>412> Сохраняйте ссылку на задачи, переданные этой функции, чтобы избежать исчезновения задачи во время выполнения. Цикл событий хранит только слабые ссылки на задачи. Задача, на которую нет других ссылок, может быть собрана сборщиком мусора в любой момент, даже до её завершения.413414Изменено в версии 3.10: Удалён параметр *loop*.415416Устарело с версии 3.10: Предупреждение об устаревании выдаётся, если *aw* не является объектом, подобным Future, и нет запущенного цикла событий.417418## [Тайм-ауты](https://python-all.ru/3.10/library/asyncio-task.html#id8)419420#### `coroutine asyncio.wait_for(aw, timeout)`421422Ожидает завершения *aw* [ожидаемого объекта](https://python-all.ru/3.10/library/asyncio-task.html#asyncio-awaitables) с таймаутом.423424Если *aw* является корутиной, она автоматически планируется как задача.425426*timeout* может быть либо `None`, либо числом с плавающей запятой или целым числом секунд ожидания. Если *timeout* равно `None`, блокирует выполнение до завершения future.427428Если происходит таймаут, он отменяет задачу и возбуждает [`asyncio.TimeoutError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.TimeoutError).429430Чтобы избежать задачи [`cancellation`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task.cancel), оберните её в [`shield()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.shield).431432Функция будет ждать, пока future не будет фактически отменена, поэтому общее время ожидания может превысить *timeout*. Если во время отмены произойдёт исключение, оно будет распространено.433434Если ожидание отменяется, future *aw* также отменяется.435436Изменено в версии 3.10: Удалён параметр *loop*.437438Пример:439440```python441async def eternity():442    # Спать в течение часа443    await asyncio.sleep(3600)444    print('yay!')445446async def main():447    # Ждать не более 1 секунды448    try:449        await asyncio.wait_for(eternity(), timeout=1.0)450    except asyncio.TimeoutError:451        print('timeout!')452453asyncio.run(main())454455# Ожидаемый вывод:456#457#     тайм-аут!458```459460Изменено в версии 3.7: Когда *aw* отменяется из-за таймаута, `wait_for` ожидает отмены *aw*. Ранее оно немедленно вызывало [`asyncio.TimeoutError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.TimeoutError).461462Изменено в версии 3.10: Удалён параметр *loop*.463464## [Примитивы ожидания](https://python-all.ru/3.10/library/asyncio-task.html#id9)465466#### `coroutine asyncio.wait(aws, *, timeout=None, return_when=ALL_COMPLETED)`467468Запускает [ожидаемые объекты](https://python-all.ru/3.10/library/asyncio-task.html#asyncio-awaitables) в *aws*\\nитерируемом объекте конкурентно и блокируется до выполнения условия, заданного\\n*return\_when*.469470Итерируемый объект *aws* не должен быть пустым.471472Возвращает два набора задач/future: `(done, pending)`.473474Использование:475476```python477done, pending = await asyncio.wait(aws)478```479480*timeout* (число с плавающей точкой или целое) позволяет указать максимальное время ожидания в секундах перед возвратом результата.481482Обратите внимание, что эта функция не вызывает [`asyncio.TimeoutError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.TimeoutError). Объекты Future или задачи, не завершённые к моменту таймаута, просто возвращаются во втором наборе.483484*return\_when* указывает, когда эта функция должна вернуть результат. Это должна быть одна из следующих констант:485486| Константа | Описание |487| --- | --- |488| `FIRST_COMPLETED` | Функция вернёт результат, когда любой future завершится или будет отменён. |489| `FIRST_EXCEPTION` | Функция вернёт результат, когда любой future завершится, возбудив исключение. Если ни один future не возбудит исключение, это эквивалентно `ALL_COMPLETED`. |490| `ALL_COMPLETED` | Функция вернёт результат, когда все future завершатся или будут отменены. |491492В отличие от [`wait_for()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.wait_for), `wait()` не отменяет futures при возникновении таймаута.493494Устарело с версии 3.8: Если любой ожидаемый объект в *aws* является корутиной, она автоматически\\nпланируется как задача. Передача объектов-корутин непосредственно в\\n`wait()` устарела, поскольку это приводит к\\n[запутанному поведению](https://python-all.ru/3.10/library/asyncio-task.html#asyncio-example-wait-coroutine).495496Изменено в версии 3.10: Удалён параметр *loop*.497498> **Примечание**499>500> `wait()` автоматически планирует корутины как задачи и затем возвращает эти неявно созданные объекты задач в `(done, pending)` наборах. Поэтому следующий код не будет работать, как ожидается:501>502> ```python503> async def foo():504>     return 42505>506> coro = foo()507> done, pending = await asyncio.wait({coro})508>509> if coro in done:510>     # Эта ветка никогда не будет выполнена!511> ```512>513> Вот как можно исправить приведённый выше фрагмент:514>515> ```python516> async def foo():517>     return 42518>519> task = asyncio.create_task(foo())520> done, pending = await asyncio.wait({task})521>522> if task in done:523>     # Теперь всё будет работать как ожидается.524> ```525526Устарело с версии 3.8, будет удалено в версии 3.11: Передача объектов-корутин непосредственно в `wait()`\\nустарела.527528Изменено в версии 3.10: Удалён параметр *loop*.529530#### `asyncio.as_completed(aws, *, timeout=None)`531532Запускает [ожидаемые объекты](https://python-all.ru/3.10/library/asyncio-task.html#asyncio-awaitables) из итерируемого *aws* одновременно. Возвращает итератор корутин. Каждую возвращённую корутину можно ожидать, чтобы получить следующий по порядку результат из итерируемого набора оставшихся ожидаемых объектов.533534Вызывает [`asyncio.TimeoutError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.TimeoutError), если время ожидания истекает до того, как все Future будут завершены.535536Пример:537538```python539for coro in as_completed(aws):540    earliest_result = await coro541    # ...542```543544Изменено в версии 3.10: Удалён параметр *loop*.545546Устарело с версии 3.10: Выдаётся предупреждение об устаревании, если не все ожидаемые объекты в итерируемом *aws* являются объектами, подобными Future, и отсутствует запущенный цикл событий.547548## [Запуск в потоках](https://python-all.ru/3.10/library/asyncio-task.html#id10)549550#### `coroutine asyncio.to_thread(func, /, *args, **kwargs)`551552Асинхронно запускает функцию *func* в отдельном потоке.553554Любые \*args и \*\*kwargs, переданные в эту функцию, напрямую передаются в *func*. Также распространяется текущий [`contextvars.Context`](https://python-all.ru/3.10/library/contextvars.html#contextvars.Context), что позволяет обращаться к контекстным переменным из потока цикла событий в отдельном потоке.555556Возвращает корутину, которую можно ожидать для получения конечного результата *func*.557558Эта корутинная функция в первую очередь предназначена для выполнения\\nфункций/методов, связанных с вводом-выводом, которые в противном случае блокировали бы цикл событий, если\\nбы они выполнялись в основном потоке. Например:559560```python561def blocking_io():562    print(f"start blocking_io at {time.strftime('%X')}")563    # Обратите внимание, что time.sleep() можно заменить любой блокирующей564    # операцией ввода-вывода, например файловыми операциями.565    time.sleep(1)566    print(f"blocking_io complete at {time.strftime('%X')}")567568async def main():569    print(f"started main at {time.strftime('%X')}")570571    await asyncio.gather(572        asyncio.to_thread(blocking_io),573        asyncio.sleep(1))574575    print(f"finished main at {time.strftime('%X')}")576577asyncio.run(main())578579# Ожидаемый вывод:580#581# запущен main в 19:50:53582# запуск blocking_io в 19:50:53583# blocking_io завершён в 19:50:54584# main завершён в 19:50:54585```586587Прямой вызов `blocking_io()` в любой корутине заблокирует цикл событий на всё время выполнения, добавив 1 секунду ко времени работы. Вместо этого, используя `asyncio.to_thread()`, можно выполнить его в отдельном потоке без блокировки цикла событий.588589> **Примечание**590>591> Из-за [GIL](https://python-all.ru/3.10/glossary.html#term-GIL) `asyncio.to_thread()` обычно можно использовать только для того, чтобы сделать функции, связанные с вводом-выводом, неблокирующими. Однако для модулей расширения, которые освобождают GIL, или альтернативных реализаций Python, у которых его нет, `asyncio.to_thread()` также можно использовать для функций, связанных с процессором.592593Новое в версии 3.9.594595## [Планирование из других потоков](https://python-all.ru/3.10/library/asyncio-task.html#id11)596597#### `asyncio.run_coroutine_threadsafe(coro, loop)`598599Отправляет корутину в указанный цикл событий. Потокобезопасно.600601Возвращает [`concurrent.futures.Future`](https://python-all.ru/3.10/library/concurrent.futures.html#concurrent.futures.Future) для ожидания результата из другого потока операционной системы.602603Эта функция предназначена для вызова из другого потока операционной системы, отличного от того, в котором работает цикл событий. Пример:604605```python606# Создать корутину607coro = asyncio.sleep(1, result=3)608609# Отправить корутину в заданный цикл610future = asyncio.run_coroutine_threadsafe(coro, loop)611612# Ожидать результат с необязательным аргументом таймаута613assert future.result(timeout) == 3614```615616Если в корутине возникло исключение, возвращаемый объект Future получит уведомление. Его также можно использовать для отмены задачи в цикле событий:617618```python619try:620    result = future.result(timeout)621except concurrent.futures.TimeoutError:622    print('The coroutine took too long, cancelling the task...')623    future.cancel()624except Exception as exc:625    print(f'The coroutine raised an exception: {exc!r}')626else:627    print(f'The coroutine returned: {result!r}')628```629630См. раздел [concurrency and multithreading](https://python-all.ru/3.10/library/asyncio-dev.html#asyncio-multithreading) документации.631632В отличие от других функций asyncio, эта функция требует явной передачи аргумента *loop* .633634Новое в версии 3.5.1.635636## [Интроспекция](https://python-all.ru/3.10/library/asyncio-task.html#id12)637638#### `asyncio.current_task(loop=None)`639640Возвращает экземпляр текущей выполняющейся [`Task`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task) или `None`, если нет выполняющейся задачи.641642Если *loop* равен `None`, используется [`get_running_loop()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.get_running_loop) для получения текущего цикла.643644Добавлено в версии 3.7.645646#### `asyncio.all_tasks(loop=None)`647648Возвращает набор ещё не завершённых объектов [`Task`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task), выполняемых циклом.649650Если *loop* равен `None`, [`get_running_loop()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.get_running_loop) используется для получения текущего цикла.651652Добавлено в версии 3.7.653654## [Объект Задачи](https://python-all.ru/3.10/library/asyncio-task.html#id13)655656#### `class asyncio.Task(coro, *, loop=None, name=None)`657658Объект [`Future-like`](https://python-all.ru/3.10/library/asyncio-future.html#asyncio.Future), выполняющий корутину Python [корутину](https://python-all.ru/3.10/library/asyncio-task.html#coroutine). Непотокобезопасный.659660Задачи используются для выполнения корутин в циклах событий. Если корутина ожидает Future, задача приостанавливает выполнение корутины и ждёт завершения Future. Когда Future *завершён*, выполнение обёрнутой корутины возобновляется.661662Циклы событий используют кооперативное планирование: цикл событий выполняет по одной задаче за раз. Пока задача ожидает завершения Future, цикл событий выполняет другие задачи, колбэки или производит операции ввода-вывода.663664Используйте высокоуровневую функцию [`asyncio.create_task()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.create_task) для создания задач или низкоуровневые функции [`loop.create_task()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.create_task) или [`ensure_future()`](https://python-all.ru/3.10/library/asyncio-future.html#asyncio.ensure_future). Ручное создание экземпляров задач не рекомендуется.665666Чтобы отменить выполняющуюся задачу, используйте метод [`cancel()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task.cancel). Его вызов приведёт к тому, что задача возбудит исключение [`CancelledError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.CancelledError) в обёрнутой корутине. Если во время отмены корутина ожидает объект Future, этот объект Future будет отменён.667668[`cancelled()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task.cancelled) можно использовать для проверки, была ли задача отменена. Метод возвращает `True`, если обёрнутая корутина не подавила исключение [`CancelledError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.CancelledError) и была действительно отменена.669670[`asyncio.Task`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task) наследует от [`Future`](https://python-all.ru/3.10/library/asyncio-future.html#asyncio.Future) все свои API, за исключением [`Future.set_result()`](https://python-all.ru/3.10/library/asyncio-future.html#asyncio.Future.set_result) и [`Future.set_exception()`](https://python-all.ru/3.10/library/asyncio-future.html#asyncio.Future.set_exception).671672Задачи поддерживают модуль [`contextvars`](https://python-all.ru/3.10/library/contextvars.html#module-contextvars). Когда создаётся задача,\\nона копирует текущий контекст и затем выполняет свою\\nкорутину в скопированном контексте.673674Изменено в версии 3.7: Добавлена поддержка модуля [`contextvars`](https://python-all.ru/3.10/library/contextvars.html#module-contextvars).675676Изменено в версии 3.8: Добавлен параметр *name*.677678Устарело с версии 3.10: Предупреждение об устаревании выводится, если *loop* не указан и нет работающего цикла событий.679680#### `cancel(msg=None)`681682Запрашивает отмену задачи.683684Обеспечивает выброс исключения [`CancelledError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.CancelledError) в обёрнутую корутину на следующем цикле событийного цикла.685686Затем корутина имеет возможность очистить ресурсы или даже отклонить\\nзапрос, подавив исключение с помощью блока [`try`](https://python-all.ru/3.10/reference/compound_stmts.html#try) …\\n… `except CancelledError` … [`finally`](https://python-all.ru/3.10/reference/compound_stmts.html#finally).\\nПоэтому, в отличие от [`Future.cancel()`](https://python-all.ru/3.10/library/asyncio-future.html#asyncio.Future.cancel), [`Task.cancel()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task.cancel) не\\nгарантирует, что задача будет отменена, хотя полное подавление отмены\\nне является распространённой практикой и активно не рекомендуется.687688Изменено в версии 3.9: Добавлен параметр *msg*.689690Следующий пример показывает, как корутины могут перехватить запрос отмены:691692```python693async def cancel_me():694    print('cancel_me(): before sleep')695696    try:697        # Ждать 1 час698        await asyncio.sleep(3600)699    except asyncio.CancelledError:700        print('cancel_me(): cancel sleep')701        raise702    finally:703        print('cancel_me(): after sleep')704705async def main():706    # Создать задачу "cancel_me"707    task = asyncio.create_task(cancel_me())708709    # Ждать 1 секунду710    await asyncio.sleep(1)711712    task.cancel()713    try:714        await task715    except asyncio.CancelledError:716        print("main(): cancel_me is cancelled now")717718asyncio.run(main())719720# Ожидаемый вывод:721#722#     cancel_me(): перед сном723#     cancel_me(): отмена сна724#     cancel_me(): после сна725#     main(): cancel_me теперь отменён726```727728#### `cancelled()`729730Return `True` if the Task is *cancelled*.731732The Task is *cancelled* when the cancellation was requested with [`cancel()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task.cancel) and the wrapped coroutine propagated the [`CancelledError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.CancelledError) exception thrown into it.733734#### `done()`735736Возвращает `True`, если задача *завершена*.737738Задача *завершена*, когда обёрнутая корутина вернула значение, возбудила исключение или задача была отменена.739740#### `result()`741742Возвращает результат задачи.743744Если задача *завершена*, возвращается результат обёрнутой корутины (или, если корутина возбудила исключение, это исключение возбуждается повторно).745746Если задача была *отменена*, этот метод возбуждает исключение [`CancelledError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.CancelledError).747748Если результат задачи ещё не доступен, этот метод возбуждает исключение [`InvalidStateError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.InvalidStateError).749750#### `exception()`751752Возвращает исключение задачи.753754Если обёрнутая корутина возбудила исключение, возвращается это исключение. Если корутина завершилась нормально, этот метод возвращает `None`.755756Если задача была *отменена*, этот метод возбуждает исключение [`CancelledError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.CancelledError).757758Если задача ещё не *завершена*, этот метод возбуждает исключение [`InvalidStateError`](https://python-all.ru/3.10/library/asyncio-exceptions.html#asyncio.InvalidStateError).759760#### `add_done_callback(callback, *, context=None)`761762Добавляет колбэк, который будет выполнен, когда задача *завершена*.763764Этот метод следует использовать только в низкоуровневом коде, основанном на колбэках.765766Подробнее см. в документации [`Future.add_done_callback()`](https://python-all.ru/3.10/library/asyncio-future.html#asyncio.Future.add_done_callback).767768#### `remove_done_callback(callback)`769770Удаляет *колбэк* из списка колбэков.771772Этот метод следует использовать только в низкоуровневом коде, основанном на колбэках.773774Подробнее см. в документации [`Future.remove_done_callback()`](https://python-all.ru/3.10/library/asyncio-future.html#asyncio.Future.remove_done_callback).775776#### `get_stack(*, limit=None)`777778Возвращает список кадров стека для этой задачи.779780Если обёрнутая корутина не завершена, возвращается стек, в котором она приостановлена. Если корутина успешно завершилась или была отменена, возвращается пустой список. Если корутина была завершена исключением, возвращается список кадров трассировки.781782Кадры всегда упорядочены от старых к новым.783784Для приостановленной корутины возвращается только один кадр стека.785786Необязательный аргумент *limit* задаёт максимальное количество возвращаемых кадров; по умолчанию возвращаются все доступные кадры. Порядок возвращаемого списка различается в зависимости от того, возвращается стек или трассировка: возвращаются новейшие кадры стека, но старейшие кадры трассировки. (Это соответствует поведению модуля traceback.)787788#### `print_stack(*, limit=None, file=None)`789790Печатает стек или трассировку для этой задачи.791792Результат аналогичен выводу модуля traceback для кадров, полученных с помощью [`get_stack()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task.get_stack).793794Аргумент *limit* передаётся непосредственно в [`get_stack()`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task.get_stack).795796Аргумент *file* – это поток ввода-вывода, в который записывается вывод; по умолчанию вывод записывается в [`sys.stdout`](https://python-all.ru/3.10/library/sys.html#sys.stdout).797798#### `get_coro()`799800Возвращает объект корутины, обёрнутый [`Task`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.Task).801802Новое в версии 3.8.803804#### `get_name()`805806Возвращает имя задачи.807808Если задаче не было явно присвоено имя, стандартная реализация задач asyncio генерирует имя по умолчанию при создании.809810Новое в версии 3.8.811812#### `set_name(value)`813814Устанавливает имя задачи.815816Аргумент *value* может быть любым объектом, который затем преобразуется в строку.817818В стандартной реализации задач имя будет видно в [`repr()`](https://python-all.ru/3.10/library/functions.html#repr)-выводе объекта задачи.819820Новое в версии 3.8.821822## [Корутины на основе генераторов](https://python-all.ru/3.10/library/asyncio-task.html#id14)823824> **Примечание**825>826> Support for generator-based coroutines is **устарела** и удалена в Python 3.11.827828Корутины на основе генераторов предшествуют синтаксису async/await. Они представляют собой генераторы Python, использующие выражения `yield from` для ожидания Future и других корутин.829830Корутины на основе генераторов следует декорировать с помощью [`@asyncio.coroutine`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.coroutine), хотя это не требуется.831832#### `@asyncio.coroutine`833834Декоратор для пометки корутин на основе генераторов.835836Этот декоратор позволяет старым корутинам на основе генераторов быть совместимыми с кодом async/await:837838```python839@asyncio.coroutine840def old_style_coroutine():841    yield from asyncio.sleep(1)842843async def main():844    await old_style_coroutine()845```846847Этот декоратор не следует использовать для [`async def`](https://python-all.ru/3.10/reference/compound_stmts.html#async-def) корутин.848849Устарело с версии 3.8, будет удалено в версии 3.11: Вместо этого используйте [`async def`](https://python-all.ru/3.10/reference/compound_stmts.html#async-def).850851#### `asyncio.iscoroutine(obj)`852853Возвращает `True`, если *obj* является [объектом корутины](https://python-all.ru/3.10/library/asyncio-task.html#coroutine).854855Этот метод отличается от [`inspect.iscoroutine()`](https://python-all.ru/3.10/library/inspect.html#inspect.iscoroutine) тем, что возвращает `True` для корутин на основе генераторов.856857#### `asyncio.iscoroutinefunction(func)`858859Возвращает `True`, если *func* является [корутинной функцией](https://python-all.ru/3.10/library/asyncio-task.html#coroutine).860861Этот метод отличается от [`inspect.iscoroutinefunction()`](https://python-all.ru/3.10/library/inspect.html#inspect.iscoroutinefunction) тем, что возвращает `True` для корутинных функций на основе генераторов, декорированных с помощью [`@coroutine`](https://python-all.ru/3.10/library/asyncio-task.html#asyncio.coroutine).862