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

Какие знаешь Awaitable объекты в asyncio?

2.8 Senior🔥 151 комментариев
#Python Core#Асинхронность и многопоточность

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

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

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

Awaitable объекты в asyncio

Awaitable — это объекты, которые можно ждать с помощью оператора await. В Python есть несколько типов Awaitable объектов.

Основные типы Awaitable

import asyncio
import inspect

# 1. Coroutines (Сопрограммы)
async def my_coroutine():
    await asyncio.sleep(1)
    return "Done"

coro = my_coroutine()
print(asyncio.iscoroutine(coro))  # True
print(inspect.iscoroutine(coro))  # True

# 2. Tasks - обёртка над coroutine
task = asyncio.create_task(my_coroutine())
print(asyncio.iscoroutine(task))  # False
print(asyncio.isfuture(task))     # True

# 3. Futures - низкоуровневый Awaitable
future = asyncio.Future()
print(asyncio.isfuture(future))   # True

Coroutines (Сопрограммы)

import asyncio

# Coroutine создаётся с помощью async def
async def fetch_data(url: str) -> str:
    await asyncio.sleep(1)
    return f"Data from {url}"

# Вызов coroutine функции создаёт coroutine object
coro = fetch_data("https://example.com")
print(type(coro))  # <class "coroutine">

# Await ждёт результат
result = await fetch_data("https://example.com")
print(result)  # "Data from https://example.com"

Tasks - управляемые coroutines

import asyncio

async def download(url: str):
    print(f"Downloading {url}...")
    await asyncio.sleep(2)
    print(f"Done: {url}")
    return f"Content from {url}"

async def main():
    # Создание задачи - coroutine запускается в фоне
    task1 = asyncio.create_task(download("url1"))
    task2 = asyncio.create_task(download("url2"))
    
    # Ждём обе задачи одновременно
    results = await asyncio.gather(task1, task2)
    print(results)
    
    # Получить текущую задачу
    current = asyncio.current_task()
    print(f"Current task: {current.get_name()}")

asyncio.run(main())

Futures - низкоуровневые Awaitable

import asyncio

async def main():
    # Future - контейнер для значения, которое будет доступно позже
    future = asyncio.Future()
    
    # Установить результат
    def set_result():
        future.set_result("Result set!")
    
    asyncio.get_event_loop().call_later(1, set_result)
    
    # Ждём результат
    result = await future
    print(result)  # "Result set!"

asyncio.run(main())

# Future с исключением
async def future_with_error():
    future = asyncio.Future()
    future.set_exception(ValueError("Something went wrong"))
    
    try:
        await future
    except ValueError as e:
        print(f"Error: {e}")

asyncio.run(future_with_error())

Типизация Awaitable

from typing import Awaitable, Coroutine
import asyncio

# Awaitable[T] - что-то, что можно ждать и получить T
def process_awaitable(coro: Awaitable[str]) -> Awaitable[str]:
    async def wrapper():
        result = await coro
        return f"Processed: {result}"
    return wrapper()

# Coroutine[YieldType, SendType, ReturnType]
async def typed_coroutine() -> str:
    return "result"

coro: Coroutine[None, None, str] = typed_coroutine()
result: str = await coro

asyncio.gather() - параллельное ожидание

import asyncio

async def task(name: str, delay: int):
    print(f"Task {name} started")
    await asyncio.sleep(delay)
    print(f"Task {name} done")
    return f"Result {name}"

async def main():
    # Ждём все задачи одновременно
    results = await asyncio.gather(
        task("A", 1),
        task("B", 2),
        task("C", 1),
        return_exceptions=True  # Не вызывает исключение
    )
    print(results)  # ["Result A", "Result B", "Result C"]

asyncio.run(main())

asyncio.wait() - более гибкое ожидание

import asyncio

async def main():
    async def slow_task(n):
        await asyncio.sleep(n)
        return f"Task {n}"
    
    tasks = [slow_task(1), slow_task(2), slow_task(3)]
    
    # Ждём когда первая задача завершится
    done, pending = await asyncio.wait(
        tasks,
        return_when=asyncio.FIRST_COMPLETED
    )
    print(f"Done: {done}")
    print(f"Pending: {pending}")
    
    # Ждём когда все завершатся
    done, pending = await asyncio.wait(
        tasks,
        return_when=asyncio.ALL_COMPLETED
    )

asyncio.run(main())

Кастомные Awaitable объекты

import asyncio

class CustomAwaitable:
    def __init__(self, value):
        self.value = value
    
    def __await__(self):
        # __await__ должна вернуть iterator
        yield from asyncio.sleep(1).__await__()
        return self.value

async def main():
    result = await CustomAwaitable("Custom result")
    print(result)  # "Custom result"

asyncio.run(main())

asyncio.wait_for() - с timeout

import asyncio
from typing import List

async def download_file(url: str) -> str:
    await asyncio.sleep(2)
    return f"Content of {url}"

async def download_with_timeout(urls: List[str], timeout: int = 5):
    tasks = [download_file(url) for url in urls]
    
    try:
        results = await asyncio.wait_for(
            asyncio.gather(*tasks),
            timeout=timeout
        )
        return results
    except asyncio.TimeoutError:
        print("Download timeout!")
        for task in tasks:
            if not task.done():
                task.cancel()

async def main():
    urls = ["url1", "url2", "url3"]
    results = await download_with_timeout(urls, timeout=10)
    print(results)

asyncio.run(main())

Различия между coroutine, task и future

import asyncio

async def my_coro():
    return "result"

async def main():
    # Coroutine - не запущен
    coro = my_coro()
    print(type(coro))  # <class "coroutine">
    
    # Task - запущен в фоне
    task = asyncio.create_task(my_coro())
    print(type(task))  # <class "Task">
    print(asyncio.isfuture(task))  # True (Task это Future)
    
    # Future - самый низкоуровневый
    future = asyncio.Future()
    print(type(future))  # <class "Future">
    
    # Все три - Awaitable, но поведение разное
    print(await coro)   # Работает
    print(await task)   # Работает
    # print(await future)  # Будет ждать вечно

asyncio.run(main())

Ключевые выводы

  • Coroutines создаются через async def, не запущены до await
  • Tasks — это coroutines, запущенные в фоне через asyncio.create_task()
  • Futures — низкоуровневые объекты для установки результатов вручную
  • Все три типа — Awaitable и могут использоваться с await
  • Лучшая практика: используй asyncio.create_task() вместо asyncio.gather() для управляемости
Какие знаешь Awaitable объекты в asyncio? | PrepBro