training-web.ruГлавнаяКатегорииО насКарта сайтаПоискТёмная тема

Категории

Работа с асинхронными функциями gather wait as_complited create_task от asyncio Python

Создано: 17 февраля 2025Автор: Егор Астапов60 просмотровСложность: сложный

Асинхронное программирование в Python позволяет выполнять множество задач одновременно без блокировки основного потока. Обычно для этого используется модуль asyncio. Давайте рассмотрим некоторые примеры асинхронных функций с использованием gather, wait, as_complited, create_task, а также способы остановки задач при сбое.

Использование asyncio.gather

asyncio.gather позволяет запускать несколько асинхронных задач параллельно и ждать их завершения.

import asyncio

async def task(name, delay):
print(f'Task {name} started, will take seconds.')
await asyncio.sleep(delay)
print(f'Task completed.')

async def main():
await asyncio.gather(
task('A', 2),
task('B', 3),
task('C', 1)
)

asyncio.run(main())

Для большого количества задач asyncio.gather подходит, когда необходимо собрать результаты нескольких независимых задач. Это хорошо для I/O-bound задач, например, при загрузке данных из нескольких источников.

Использование asyncio.wait

asyncio.wait позволяет ожидать завершения нескольких задач и дает гибкость в обработке результатов

import asyncio

async def task(name, delay):
print(f'Task started.')
await asyncio.sleep(delay)
print(f'Task completed.')

async def main():
tasks = [
asyncio.create_task(task('A', 2)),
asyncio.create_task(task('B', 3)),
asyncio.create_task(task('C', 1))
]

done, pending = await asyncio.wait(tasks)

for task in done:
print(f'Done: {task.get_name()}')

asyncio.run(main())

Для большого количества задач asyncio.wait полезен, когда вы хотите обрабатывать задачи по мере их завершения и быть в курсе того, какие задачи всё ещё выполняются.

Использование asyncio.as_completed

asyncio.as_completed — это полезная утилита в Python, которая позволяет выполнять асинхронные задачи в параллельном режиме и обрабатывать результаты по мере их завершения. Она возвращает итератор, который генерирует задачи по мере их завершения, что позволяет вам получать результаты незамедлительно, не дожидаясь завершения всех задач.

Как работает asyncio.as_completed? Asyncio.as_completed принимает итерируемый объект, содержащий корутины или задачи, и возвращает итератор, который вы можете использовать в for цикле или при помощи await.

import asyncio

async def fetch_data(index):
await asyncio.sleep(index) # Имитация задержки
return f"Data {index}"

async def main():
tasks = [fetch_data(i) for i in range(5)]
for completed in asyncio.as_completed(tasks):
result = await completed
print(result)

asyncio.run(main())

Подходит ли он для большого списка задач? Asyncio.as_completed подходит для обработки множества асинхронных задач. Однако при работе с большими задачами стоит учитывать следующие моменты:

  1. Использование ресурсов: В зависимости от реализаций задач, большое количество одновременно выполняемых задач может привести к высокому потреблению ресурсов (CPU, память, сети). Особенно, если задачи выполняют тяжелые вычисления или требуют много сетевого ввода-вывода.
  2. Управление количеством одновременно выполняемых задач: Если вы хотите ограничить количество одновременно выполняемых задач, используйте семафоры или ограниченные очереди (например, `asyncio.Semaphore` или `asyncio.Queue`).

Использование asyncio.create_task

asyncio.create_task позволяет создать задачу, которая будет исполняться параллельно.

import asyncio

async def task(name, delay):
print(f'Task started.')
await asyncio.sleep(delay)
if name == 'B':
raise Exception('Task B failure!')
print(f'Task completed.')

async def main():
task_a = asyncio.create_task(task('A', 2))
task_b = asyncio.create_task(task('B', 3))
task_c = asyncio.create_task(task('C', 1))

tasks = [task_a, task_b, task_c]

for task in tasks:
try:
await task
except Exception as e:
print(f'Error occurred: {e}')

asyncio.run(main())

Для тяжелых задач: create_task позволяет выполнять тяжелые длительные задачи, например, обработку больших файлов или сетевые запросы, параллельно с другими задачами. Для большого количества задач asyncio.create_task не подходит.

Остановка задач при сбое

Чтобы остановить все задачи при возникновении исключения в одной из них, вы можете использовать конструкцию `try...except`, как показано в последнем примере. Если задача завершилась с ошибкой, выбрасывается исключение, и вы можете обработать его и тем самым завершить выполнение программы или откатить изменения.

Также можно использовать asyncio.wait с параметром return_when=asyncio.FIRST_EXCEPTION, чтобы завершить все задачи при первой ошибке:

done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)

Это позволит прекратить выполнение задач, как только одна из них завершится с ошибкой.

Асинхронное программирование в Python очень полезно для работы с задачами, которые могут занимать длительное время, особенно при взаимодействии с I/O: сетевыми запросами, чтением и записью файлов и т.п. Примеры, описанные выше, помогут вам начать использовать асинхронные функции в ваших проектах.

Комментарии

реклама