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

Что такое Task в asyncio?

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

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

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

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

Task в asyncio — Асинхронное выполнение корутин

Task — это объект, который оборачивает корутину и управляет её асинхронным выполнением в event loop. Это основной способ запуска нескольких корутин параллельно.

Зачем нужны Task'и

Сама по себе корутина — это просто объект с инструкциями. Чтобы её выполнить, нужно:

  1. Создать event loop
  2. Запустить корутину в loop'е
  3. Управлять её жизненным циклом

Task автоматизирует этот процесс:

import asyncio

async def fetch_data(url):
    print(f'Загружаю {url}')
    await asyncio.sleep(2)
    return f'Данные от {url}'

# ❌ Плохо: корутина не выполняется
coro = fetch_data('https://api.example.com')
print(coro)  # <coroutine object fetch_data at 0x...>

# ✅ Хорошо: Task выполняет корутину
async def main():
    task = asyncio.create_task(fetch_data('https://api.example.com'))
    result = await task
    print(result)  # Данные от https://api.example.com

asyncio.run(main())

Создание Task

1. asyncio.create_task() — Рекомендуемый способ

async def main():
    # Создаёшь task и сразу начинает выполняться
    task = asyncio.create_task(fetch_data('url1'))
    
    # Пока task выполняется в фоне, ты можешь делать другое
    print('Task запущена')
    
    # Когда тебе нужен результат, ждёшь
    result = await task
    print(result)

asyncio.run(main())

2. asyncio.ensure_future() — Старый способ (не используй)

task = asyncio.ensure_future(fetch_data('url'))

3. Прямой await — Последовательно

async def main():
    result = await fetch_data('url')
    # Ждёшь, пока завершится перед тем, как продолжить

Параллельное выполнение с Task'ами

Основное преимущество Task'ов — можно запустить несколько параллельно:

import asyncio
import time

async def fetch(url, delay):
    print(f'Начинаю загружать {url}')
    await asyncio.sleep(delay)
    print(f'Завершил {url}')
    return f'Данные {url}'

async def main():
    start = time.time()
    
    # Создаём 3 task'и
    task1 = asyncio.create_task(fetch('url1', 2))
    task2 = asyncio.create_task(fetch('url2', 2))
    task3 = asyncio.create_task(fetch('url3', 2))
    
    # Ждём все три параллельно (2 сек, не 6)
    results = await asyncio.gather(task1, task2, task3)
    
    elapsed = time.time() - start
    print(f'Заняло {elapsed:.1f} сек')
    print(results)

asyncio.run(main())

# Output:
# Начинаю загружать url1
# Начинаю загружать url2
# Начинаю загружать url3
# Завершил url1
# Завершил url2
# Завершил url3
# Заняло 2.0 сек

asyncio.gather() vs asyncio.wait()

gather() — Простой способ

# Жди все task'и
results = await asyncio.gather(task1, task2, task3)

# Со скрытием ошибок
results = await asyncio.gather(
    task1, task2, task3,
    return_exceptions=True
)

wait() — Больше контроля

done, pending = await asyncio.wait(
    [task1, task2, task3],
    return_when=asyncio.FIRST_COMPLETED  # Вернуть как только одна завершится
)

for task in done:
    print(task.result())

Состояния Task'и

task = asyncio.create_task(fetch_data('url'))

print(task.done())  # False — ещё выполняется
# ... ждём ...
print(task.done())  # True — завершена

if task.done():
    print(task.result())  # Результат
    # или
    try:
        print(task.exception())  # Если была ошибка
    except:
        pass

Отмена Task'и

async def long_operation():
    try:
        for i in range(10):
            print(i)
            await asyncio.sleep(1)
    except asyncio.CancelledError:
        print('Task была отменена')
        raise

async def main():
    task = asyncio.create_task(long_operation())
    await asyncio.sleep(3)
    task.cancel()  # Отмени task
    
    try:
        await task
    except asyncio.CancelledError:
        print('Task отменена и ошибка обработана')

asyncio.run(main())

Практический пример: Веб-краулер

import asyncio
import aiohttp

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

async def crawl_urls(urls):
    tasks = []
    async with aiohttp.ClientSession() as session:
        for url in urls:
            task = asyncio.create_task(fetch_url(session, url))
            tasks.append(task)
        
        # Загружай все параллельно
        results = await asyncio.gather(*tasks)
    
    return results

url_list = ['https://example.com', 'https://google.com', 'https://github.com']
results = asyncio.run(crawl_urls(url_list))

На интервью

Ответи так:

"Task — это обёртка вокруг корутины, которая запускает её в event loop и управляет жизненным циклом. Основное назначение — запускать несколько корутин параллельно с помощью asyncio.create_task(). Task можно отменить, получить результат, или обработать исключения. Это ключевое понятие asyncio."

Что такое Task в asyncio? | PrepBro