← Назад к вопросам

Зачем нужен gather в asyncio?

1.7 Middle🔥 241 комментариев
#Python Core#Асинхронность и многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

asyncio.gather() — для параллельного выполнения асинхронных задач

asyncio.gather() — это функция для запуска нескольких асинхронных операций параллельно (на самом деле конкурентно) и ожидания их завершения. Это один из самых полезных инструментов в asyncio.

Базовый пример

import asyncio

async def fetch_data(name: str, delay: int):
    """Имитирует асинхронную операцию (HTTP запрос)"""
    print(f"[{name}] Starting...")
    await asyncio.sleep(delay)
    print(f"[{name}] Done after {delay}s")
    return f"Result from {name}"

async def main():
    results = await asyncio.gather(
        fetch_data("Task1", 2),
        fetch_data("Task2", 1),
        fetch_data("Task3", 3)
    )
    print("All results:", results)

asyncio.run(main())

Без gather выполнялось 6 секунд (2+1+3), с gather — только 3 секунды (maximum).

Зачем нужен gather

1. Экономия времени при параллельных I/O операциях

import aiohttp
import asyncio

async def fetch_url(session, url):
    async with session.get(url) as response:
        return await response.json()

async def fetch_multiple_apis():
    urls = ["https://api.github.com/users/github", "https://api.github.com/users/google"]
    async with aiohttp.ClientSession() as session:
        results = await asyncio.gather(*[fetch_url(session, url) for url in urls])
    return results

Если каждый запрос занимает 0.5 сек: последовательно 1.5 сек, с gather 0.5 сек.

2. Получение результатов в определённом порядке

gather() возвращает результаты в том же порядке, что вы передали задачи.

async def main():
    task1_result, task2_result, task3_result = await asyncio.gather(
        fetch_data("API1"),
        fetch_data("API2"),
        fetch_data("API3")
    )

3. Работа с динамическим списком задач

async def process_items(items):
    tasks = [process_one_item(item) for item in items]
    results = await asyncio.gather(*tasks)
    return results

Параметры gather

return_exceptions=True — не падать при ошибке

async def task_that_fails():
    raise ValueError("Something went wrong")

async def safe_task():
    return "Success"

async def main():
    results = await asyncio.gather(
        task_that_fails(),
        safe_task(),
        return_exceptions=True
    )
    print(results)
    for i, result in enumerate(results):
        if isinstance(result, Exception):
            print(f"Task {i} failed: {result}")
        else:
            print(f"Task {i}: {result}")

Отличие от других способов

1. gather vs create_task

# gather — ждём все задачи
results = await asyncio.gather(task1, task2, task3)

# create_task — запускаем, но не ждём
task1 = asyncio.create_task(coro1)
await task1

2. gather vs wait

# gather — просто ждёт и возвращает результаты
results = await asyncio.gather(task1, task2)

# wait — контроль за процессом завершения
done, pending = await asyncio.wait([task1, task2])

Практический пример: обработка запросов к БД

import asyncpg

async def get_user_with_data(pool, user_id):
    async with pool.acquire() as conn:
        user = await conn.fetchrow("SELECT * FROM users WHERE id = $1", user_id)
        posts = await conn.fetch("SELECT * FROM posts WHERE user_id = $1", user_id)
    return {"user": user, "posts": posts}

async def get_multiple_users(pool, user_ids):
    results = await asyncio.gather(
        *[get_user_with_data(pool, uid) for uid in user_ids],
        return_exceptions=True
    )
    return results

Итог

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

Зачем нужен gather в asyncio? | PrepBro