← Назад к вопросам
Как работает асинхронное программирование (async/await)?
2.0 Middle🔥 161 комментариев
#Python Core#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает асинхронное программирование (async/await)
Базовая идея
Обычный синхронный код блокирует выполнение:
# Синхронно: ждём 2 секунды
result = requests.get("https://api.example.com/data")
print(result.json())
print("Готово") # Выполнится только через 2 сек
Асинхронно позволяет выполнять другие задачи пока ждём:
# Асинхронно: запрос идёт в фоне
async def main():
result = await fetch_data()
print(result)
print("Готово")
Синтаксис: async/await
async def my_async_function():
print("Это async функция")
await asyncio.sleep(1)
return "Результат"
import asyncio
result = asyncio.run(my_async_function())
print(result)
Event Loop (циклик событий)
Это главный механизм:
import asyncio
async def task1():
print("Task 1: start")
await asyncio.sleep(2)
print("Task 1: finish")
async def task2():
print("Task 2: start")
await asyncio.sleep(1)
print("Task 2: finish")
async def main():
await asyncio.gather(task1(), task2())
asyncio.run(main())
# Вывод: обе задачи бегут параллельно
# Всего 2 сек (не 3!)
Как это работает
Event loop - это циклик:
- Запускает задачу 1
- Задача 1 встречает await - отдаёт управление
- Event loop берёт задачу 2, запускает её
- Задача 2 встречает await - отдаёт управление
- Event loop проверяет: готовы ли данные для задачи 1?
- Когда готовы - запускает продолжение задачи 1
Ключь: когда задача ждёт (await), она отдаёт управление другим задачам.
Практические примеры
Множество HTTP запросов
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.json()
async def main():
urls = [
"https://api.example.com/1",
"https://api.example.com/2",
"https://api.example.com/3",
]
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
results = asyncio.run(main())
# Время: ~1 сек вместо 3 сек
Timeout и обработка ошибок
async def fetch_with_timeout():
try:
result = await asyncio.wait_for(
fetch_data(),
timeout=5.0
)
return result
except asyncio.TimeoutError:
print("Запрос слишком долгий")
return None
asyncio.gather vs asyncio.wait
# gather: ждём все результаты
results = await asyncio.gather(task1(), task2(), task3())
# wait: ждём первые N завершённых
done, pending = await asyncio.wait(
[task1(), task2(), task3()],
return_when=asyncio.FIRST_COMPLETED
)
Важные отличия
| Синхронный | Асинхронный |
|---|---|
| def func() | async def func() |
| result = func() | result = await func() |
| Блокирует процесс | Переключается между задачами |
| Простой тред | Один процесс, один тред |
Когда использовать async
✅ Используй:
- I/O операции (HTTP, БД, файлы)
- Множество параллельных операций
- Высокий параллелизм на одном сервере
❌ НЕ используй:
- CPU-intensive задачи (нужны processes)
- Простые скрипты без I/O
- Когда нет асинхронной библиотеки
Частые проблемы
Забыл await
async def bad():
result = fetch_data() # НЕПРАВИЛЬНО!
print(result) # <coroutine object>
async def good():
result = await fetch_data()
print(result) # Реальные данные
Смешивание sync и async
async def bad():
time.sleep(2) # БЛОКИРУЕТ event loop!
async def good():
await asyncio.sleep(2) # Не блокирует
Race conditions
counter = 0
async def bad_increment():
global counter
counter += 1 # Может быть race condition
lock = asyncio.Lock()
async def safe_increment():
global counter
async with lock:
counter += 1 # Безопасно
FastAPI пример
from fastapi import FastAPI
app = FastAPI()
@app.get("/data")
async def get_data():
result = await fetch_from_api()
return {"data": result}
Производительность
Asyncio даёт преимущество только при I/O:
# 10 HTTP запросов по 1 сек каждый:
# Sync: 10 сек
# Async: ~1 сек (параллельно)
# CPU вычисления:
# Sync: 10 сек
# Async: 10 сек (всё равно на одном ядре)
Для CPU используй multiprocessing.
Итог
Async/await позволяет:
- Запускать много I/O операций одновременно
- На одинthread
- Писать чистый код
- Эффективно использовать ресурсы
Ключевые правила:
- Event loop переключается между задачами на await
- Никогда не блокируй (только async libraries)
- Для CPU используй multiprocessing
- ВСЕГДА await асинхронные функции