Асинхронное программирование
Основы async/await
import asyncio # импорт асинхронного модуля
# Асинхронная функция (корутина)
async def greet(name: str) -> str: # асинхронная функция (корутина)
await asyncio.sleep(1) # асинхронная пауза
return f"Привет, {name}!" # возврат значения
# Запуск корутины
result = asyncio.run(greet("Мир")) # запуск асинхронной программы
print(result) # вывод в консоль
Параллельный запуск
async def fetch_data(url: str) -> str: # асинхронная функция (корутина)
print(f"Загрузка {url}") # вывод в консоль
await asyncio.sleep(2) # асинхронная пауза
return f"Данные {url}" # возврат значения
async def main(): # асинхронная функция (корутина)
# Последовательно
r1 = await fetch_data("url1") # присваивание
r2 = await fetch_data("url2") # присваивание
# Параллельно
results = await asyncio.gather( # параллельный запуск корутин
fetch_data("url1"),
fetch_data("url2"),
fetch_data("url3"),
)
print(results) # вывод в консоль
asyncio.run(main()) # запуск асинхронной программы
asyncio.create_task — фоновые задачи
async def background_work(): # асинхронная функция (корутина)
while True: # цикл с предусловием
print("Работаю...") # вывод в консоль
await asyncio.sleep(5) # асинхронная пауза
async def main(): # асинхронная функция (корутина)
# Запуск в фоне
task = asyncio.create_task(background_work()) # создание фоновой задачи
await asyncio.sleep(12) # асинхронная пауза
task.cancel()
asyncio.run(main()) # запуск асинхронной программы
Тайм-ауты
async def slow_operation(): # асинхронная функция (корутина)
await asyncio.sleep(10) # асинхронная пауза
return "Готово" # возврат значения
async def main(): # асинхронная функция (корутина)
try: # начало блока с обработкой исключений
result = await asyncio.wait_for(slow_operation(), timeout=5) # ожидание с таймаутом
except asyncio.TimeoutError: # обработка исключения
print("Таймаут! Операция отменена") # вывод в консоль
asyncio.run(main()) # запуск асинхронной программы
Асинхронные генераторы
async def async_counter(n: int): # асинхронная функция (корутина)
for i in range(n): # цикл по элементам
await asyncio.sleep(0.5) # асинхронная пауза
yield i # генерация значения
async def main(): # асинхронная функция (корутина)
async for value in async_counter(5): # асинхронная итерация
print(value) # 0, 1, 2, 3, 4 с интервалом 0.5с
asyncio.run(main()) # запуск асинхронной программы
Работа с сетью (aiohttp)
import aiohttp # импорт асинхронного HTTP-клиента
import asyncio # импорт асинхронного модуля
async def fetch(session, url): # асинхронная функция (корутина)
async with session.get(url) as response: # асинхронный контекстный менеджер
return await response.json() # возврат значения
async def main(): # асинхронная функция (корутина)
urls = ["https://api.github.com"] * 5 # инициализация списка
async with aiohttp.ClientSession() as session: # асинхронный контекстный менеджер
tasks = [fetch(session, url) for url in urls] # списковое включение
results = await asyncio.gather(*tasks) # параллельный запуск корутин
asyncio.run(main()) # запуск асинхронной программы
Синхронное vs асинхронное
| Синхронно | Асинхронно |
def func() | async def func() |
func() | await func() |
result | await result |
for | async for |
with | async with |
time.sleep() | await asyncio.sleep() |
asyncio vs threading vs multiprocessing
# asyncio — для I/O-bound задач (сеть, файлы, БД)
# threading — для I/O-bound, но с GIL
# multiprocessing — для CPU-bound задач (реальные потоки ОС)
import asyncio # импорт асинхронного модуля
import threading # импорт модуля
import multiprocessing # импорт модуля
# asyncio — одна корутина за раз, переключение по await
# threading — переключение по прерыванию ОС
# multiprocessing — параллельное выполнение на всех ядрах
Синхронизация в asyncio
import asyncio # импорт асинхронного модуля
async def worker(name, lock): # асинхронная функция (корутина)
async with lock: # асинхронный контекстный менеджер
print(f"{name} работает") # вывод в консоль
await asyncio.sleep(1) # асинхронная пауза
async def main(): # асинхронная функция (корутина)
lock = asyncio.Lock() # асинхронный мьютекс
tasks = [worker(f"W{i}", lock) for i in range(3)] # последовательность чисел
await asyncio.gather(*tasks) # параллельный запуск корутин
asyncio.run(main()) # запуск асинхронной программы