Функция wait()



Функция asyncio.wait(list_task) имеет функционал, схожий с asyncio.gather(). Обе функции асинхронно запускают переданные awaitable-объекты. Для написания парсеров нет большой разницы, какую из этих функций использовать, так как мы будем выполнять только запросы к серверу и сохранение данных в файл.

Так в чём же разница?

asyncio.gather(aws) фокусируется на сборе результатов: она ждёт выполнения переданных в него, aws(awaitable-объектов) и возвращает список полученныx результатов работы для этих объектов. Каждая задача или группа задач может быть отменена методом .cancel(). Для написания парсеров мы этим функционалом пользоваться не будем. Это высокоуровневое решение.

done, pending = asyncio.wait(aws,timeout=2) также ждёт awaitable-объекты(Futures или Tasks), но возвращает два множества (set) из Tasks/Futures: done и pending (выполненные и ожидающие выполнения),  соответственно.

Еще одним отличием является то, что в asyncio.wait() может быть использован параметр timeout.

Когда время ожидания сопрограммы истекает, исключение TimeoutError не вызывается. Вместо этого, фьючерсы или задачи, которые не были выполнены в момент тайм-аута, просто возвращаются во второй набор.

Мы можем немного модифицировать код с прошлого этапа и заменить функцию gather() функцией wait().

import asyncio
import random
import time

async def one():
    # Получаем текущее время в секундах с начала эпохи.
    start = time.time()
    await asyncio.sleep((sleep_time := random.randint(1, 3)))

    # Получаем имя текущей задачи и выводим сообщение с временем ее выполнения:
    print(f'{asyncio.current_task().get_name()} ({sleep_time=}) выполнена за {time.time() - start}')

async def main():
    # Создание списка задач.
    lst_tasks = []
    for x in range(10):
        # Корутины должны быть явно обернуты в Task.
        task = asyncio.create_task(one(), name=f'Задача_{x}')
        lst_tasks.append(task)
    done, pending = await asyncio.wait(lst_tasks, timeout=2)
    print(f'Не успели выполниться: {[task.get_name() for task in pending]}')

    # Даем время выполниться оставшимся задачам
    await asyncio.sleep(3)
asyncio.run(main())

Вывод:

Задача_1 (sleep_time=1) выполнена за 1.012650489807129
Задача_5 (sleep_time=1) выполнена за 1.012650489807129
Задача_3 (sleep_time=1) выполнена за 1.012650489807129
Задача_8 (sleep_time=1) выполнена за 1.012650489807129
Задача_6 (sleep_time=1) выполнена за 1.012650489807129
Не успели выполниться: ['Задача_7', 'Задача_4', 'Задача_0', 'Задача_2', 'Задача_9']
Задача_4 (sleep_time=2) выполнена за 2.0007762908935547
Задача_9 (sleep_time=2) выполнена за 2.0007762908935547
Задача_7 (sleep_time=2) выполнена за 2.0007762908935547
Задача_2 (sleep_time=3) выполнена за 3.010802984237671
Задача_0 (sleep_time=3) выполнена за 3.010802984237671

Обратите внимание, что те задачи, которые попадают в множество pending(ожидающие выполнения) продолжают свое выполнение после срабатывания таймаута.

P.S. При выполнении этого кода вы можете столкнуться с ситуацией, когда одна или несколько задач с sleep_time=2 окажется в множестве done (туда попадет всё, что успеет выполниться в пределах таймаута), а  другая (другие) с тем же sleep_time=2 — в pending.

. . .
Задача_6 (sleep_time=1) выполнена за 1.0119240283966064
Задача_7 (sleep_time=1) выполнена за 1.0119240283966064
Задача_5 (sleep_time=2) выполнена за 2.025589942932129
Не успели выполниться: ['Задача_8', 'Задача_0', 'Задача_2']
Задача_2 (sleep_time=2) выполнена за 2.025589942932129
Задача_0 (sleep_time=3) выполнена за 3.0177180767059326
. . .

Таким образом, фактическое время выполнения задач и момент, когда истекает таймаут, определяют, в какое множество (done или pending) попадет каждая задача. То, что задачи с одинаковым sleep_time могут попадать в разные списки, связано с тем, что время их старта может незначительно отличаться из-за асинхронной природы выполнения, а также из-за внутренних задержек и точности таймера таймаута.



Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: