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

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

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

Синтаксис:

import asyncio

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

Параметры:

  • aws - множество объектов ожидания,
  • loop=None - параметры цикла,
  • 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

!!! Обратите внимание, что функция asyncio.wait() автоматически назначает сопрограммы как задачи, а затем возвращает неявно созданные объекты задач в кортеже их двух множеств (done, pending). Следовательно, код ниже не будет работать должным образом:

# псевдокод
async def foo():
    return 42 

coro = foo()
done, pending = await asyncio.wait({coro})

if coro in done:
    # Эта ветка никогда не запустится!

Вот как можно исправить приведенный выше фрагмент:

# псевдокод
async def foo():
    return 42

task = asyncio.create_task(foo())
done, pending = await asyncio.wait({task})

if task in done:
    # Теперь все будет работать как положено.

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

Функция 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 = [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 получены.