Сообщить об ошибке.

Функция wait() модуля asyncio в Python

Приостановка выполнение задач по таймауту или условию

Синтаксис:

import asyncio

done, pending = asyncio.wait(aws, *, loop=None, timeout=None, 
                             return_when=ALL_COMPLETED)

Параметры:

  • aws - множество объектов ожидания,
  • loop=None - параметры цикла (удален с версии Python 3.10),
  • timeout=None - максимальным количеством секунд ожидания,
  • return_when=ALL_COMPLETED - когда функция должна возвратить результат.

Возвращаемое значение:

Описание поведения asyncio.wait:

Функция wait() модуля asyncio одновременно запускает awaitable-объекты (преимущественно задачи Task) из переданного множества aws и производит блокировку выполнения программы до выполнения условия, указанного в аргументе return_when.

Возвращает кортеж из двух множеств Task/Future в виде (done, pending).

# псевдокод
done, pending = await asyncio.wait(aws)

Аргумент timeout (float или int) в секундах, если он указан, можно использовать для управления временем ожидания результатов задач, из множества aws, прежде чем приостановить не выполненные задачи.

Обратите внимание, что функция asyncio.wait() не вызывает исключение asyncio.TimeoutError. Задачи, которые не успели выполнится по истечении timeout, приостанавливают свое выполнение и возвращаются во втором множестве pending. В последствии, можно возобновить выполнение приостановленных задач.

Аргумент return_when указывает, когда функция asyncio.wait() должна возвратить результат. Это должна быть одна из следующих констант:

КонстантаОписание
asyncio.FIRST_COMPLETEDФункция возвратит результат, когда любой из Future завершится или был отменен.
asyncio.FIRST_EXCEPTIONФункция возвратит результат, когда любой из Future завершится созданием исключения. Если никакое Future не вызывает исключения, то эта константа эквивалентна asyncio.ALL_COMPLETED.
asyncio.ALL_COMPLETEDФункция возвратит результат, когда все Future завершатся или будут отменены.

В отличие от функции asyncio.wait_for(), asyncio.wait() не отменяет, а приостанавливает задачи при наступлении таймаута.

Изменено в Python 3.8: Прямая передача сопрограмм в функцию asyncio.wait() не рекомендуется, так как это приводит к запутанному поведению. Если какой-либо объект, ожидающий результатов в *aws является сопрограммой, то он автоматически назначается как задача Task.

Устарело с Python 3.8: аргумент loop устарел и будет удален в Python 3.10

Изменено в Python 3.10: удален аргумент loop.

Изменено в Python 3.11: запрещена прямая передача объектов сопрограммы в asyncio.wait().

Изменено в Python 3.12: добавлена поддержка генераторов, выдающих задания.

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

Функция asyncio.wait_for() поддерживает приостановку выполнения задач, после получения результата задачи, которая вернула их первой или после указанного таймаута, что обеспечивает более низкий уровень точности операций:

import asyncio, random

async def worker(tag):
    """Основная сопрограмма"""
    print('Run:', tag)
    # эмитируем ожидание ответа сервера случайным
    # образом при помощи модуля `random` 
    await asyncio.sleep(random.uniform(0.5, 5))
    print('Done:', tag)
    return tag

async def main():
    """Точка входа в программу"""
    # создаем и планируем асинхронный запуск задач
    tasks = [asyncio.create_task(worker(tag)) for tag in range(1, 8)]

    # запускаем созданные задачи до получения любого первого результата
    done, pending1 = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
    print("Приостановка задач, после получения первого результата:")
    for future in done:
        res = future.result()
        print(f'  Результаты задачи №{res} получены.')
    print("Кол-во приостановленных задач:", len(pending1), '\n')

    # запускаем приостановленные задачи с таймаутом в 2 сек
    done, pending2 = await asyncio.wait(pending1, timeout=2)
    print("Дальнейшие результаты после таймаута в 2 сек:")
    for future in done:
        res = future.result()
        print(f'  Результаты задачи №{res} получены.')
    print("Кол-во остановленных задач после 2 сек. работы:", len(pending2), '\n')

    done, _ = await asyncio.wait(pending2)
    print("Получаем оставшиеся результаты:")
    for future in done:
        res = future.result()
        print(f'Результаты задачи №{res} получены.')

if __name__ == "__main__":
    # запускаем цикл событий.
    asyncio.run(main())
    
# Run: 1
# Run: 4
# Run: 5
# Run: 3
# Run: 6
# Run: 2
# Run: 7
# Done: 4
# Приостановка задач, после получения первого результата:
#   Результаты задачи №4 получены.
# Кол-во приостановленных задач: 6 

# Done: 7
# Done: 6
# Done: 1
# Done: 5
# Дальнейшие результаты после таймаута в 2 сек:
#   Результаты задачи №1 получены.
#   Результаты задачи №7 получены.
#   Результаты задачи №5 получены.
#   Результаты задачи №6 получены.
# Кол-во остановленных задач после 2 сек. работы: 2 

# Done: 2
# Done: 3
# Получаем оставшиеся результаты:
#   Результаты задачи №2 получены.
#   Результаты задачи №3 получены.