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

Какие задачи хорошо подходят для асинхронного выполнения?

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

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

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

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

Какие задачи хорошо подходят для асинхронного выполнения

Асинхронное выполнение идеально подходит для задач, которые предполагают ожидание внешних событий. Вместо блокирования потока выполнения можно переключиться на другую задачу.

Типы задач для асинхронности

1. I/O операции (наиболее подходящие)

Это основной сценарий для асинхронности. Когда программа ждет ответа от внешнего ресурса, она может выполнять другую работу.

HTTP запросы:

import asyncio
import aiohttp

async def fetch_user(session, user_id):
    """Асинхронный запрос данных пользователя"""
    url = f'https://api.example.com/users/{user_id}'
    async with session.get(url) as response:
        return await response.json()

async def fetch_all_users(user_ids):
    """Параллельная загрузка нескольких пользователей"""
    async with aiohttp.ClientSession() as session:
        # Все запросы выполняются параллельно
        tasks = [fetch_user(session, uid) for uid in user_ids]
        return await asyncio.gather(*tasks)

# Использование
users = asyncio.run(fetch_all_users([1, 2, 3, 4, 5]))

Работа с базой данных:

import asyncpg

async def fetch_from_db():
    """Асинхронный запрос к БД"""
    # Подключение (может быть длительным)
    conn = await asyncpg.connect('postgresql://user:password@localhost/db')
    
    try:
        # Запрос (также может быть длительным)
        rows = await conn.fetch('SELECT * FROM users WHERE active = true')
        return rows
    finally:
        await conn.close()

# Можно обрабатывать много запросов одновременно
results = asyncio.run(fetch_from_db())

Чтение/запись файлов:

import aiofiles

async def read_file_async(filename):
    """Асинхронное чтение файла"""
    async with aiofiles.open(filename, 'r') as f:
        content = await f.read()  # Не блокирует другие задачи
        return content

async def process_multiple_files(filenames):
    """Обработка нескольких файлов параллельно"""
    tasks = [read_file_async(f) for f in filenames]
    return await asyncio.gather(*tasks)

2. Сетевые операции

import asyncio
import socket

async def send_data_to_server(host, port, data):
    """Асинхронная отправка данных"""
    reader, writer = await asyncio.open_connection(host, port)
    
    writer.write(data.encode())
    await writer.drain()  # Убедиться, что данные отправлены
    
    response = await reader.readline()  # Ждем ответ без блокирования
    
    writer.close()
    await writer.wait_closed()
    return response.decode()

async def handle_multiple_connections(connections):
    """Обработка нескольких соединений параллельно"""
    tasks = [send_data_to_server(h, p, d) for h, p, d in connections]
    return await asyncio.gather(*tasks)

3. Веб-приложения

from fastapi import FastAPI
from fastapi.responses import JSONResponse
import asyncio

app = FastAPI()

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    """Асинхронный эндпоинт"""
    # Пока один запрос ждет БД, другие обрабатываются
    user_data = await fetch_from_db(user_id)
    return user_data

@app.post("/bulk-import")
async def bulk_import(items: list):
    """Асинхронная обработка нескольких элементов"""
    # Все элементы загружаются параллельно
    tasks = [import_item(item) for item in items]
    results = await asyncio.gather(*tasks)
    return {"imported": len(results)}

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

import asyncio
import aiohttp
from bs4 import BeautifulSoup

async def fetch_page(session, url):
    """Загрузить одну страницу"""
    async with session.get(url) as response:
        return await response.text()

async def parse_page(html):
    """Парсить HTML"""
    soup = BeautifulSoup(html, 'html.parser')
    # Обработка в фоновом потоке
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(None, lambda: soup.find_all('h1'))

async def scrape_urls(urls):
    """Скрейпить несколько URL параллельно"""
    async with aiohttp.ClientSession() as session:
        # Загрузка всех страниц одновременно
        pages = await asyncio.gather(*[
            fetch_page(session, url) for url in urls
        ])
        
        # Парсинг всех страниц параллельно
        results = await asyncio.gather(*[
            parse_page(page) for page in pages
        ])
        
        return results

# Использование
urls = ['https://example.com/page1', 'https://example.com/page2']
headings = asyncio.run(scrape_urls(urls))

Когда НЕ использовать асинхронность

# ❌ CPU-bound операции (вычисления) — асинхронность не поможет
import asyncio

async def calculate_fibonacci(n):
    """Это НЕ хорошо для асинхронности"""
    if n <= 1:
        return n
    return await calculate_fibonacci(n-1) + await calculate_fibonacci(n-2)

# ✅ Для CPU-bound используй многопроцессность
from multiprocessing import Pool

def calculate_fibonacci_sync(n):
    """Синхронная версия"""
    if n <= 1:
        return n
    return calculate_fibonacci_sync(n-1) + calculate_fibonacci_sync(n-2)

# Параллельно на разных процессах
with Pool() as pool:
    results = pool.map(calculate_fibonacci_sync, [30, 31, 32])

Сравнение подходов

import time
import asyncio
import aiohttp
import requests
from concurrent.futures import ThreadPoolExecutor

urls = ['https://httpbin.org/delay/2'] * 10

# Вариант 1: Синхронный (медленный)
def sync_requests():
    start = time.time()
    for url in urls:
        requests.get(url)  # 20 секунд (10 * 2)
    return time.time() - start

# Вариант 2: Многопоточность (быстрее)
def threaded_requests():
    start = time.time()
    with ThreadPoolExecutor(max_workers=5) as executor:
        list(executor.map(requests.get, urls))  # 4 секунды
    return time.time() - start

# Вариант 3: Асинхронность (самый быстрый)
async def async_requests():
    start = time.time()
    async with aiohttp.ClientSession() as session:
        tasks = [session.get(url) for url in urls]
        await asyncio.gather(*tasks)  # 2 секунды
    return time.time() - start

print(f"Синхронно: {sync_requests():.1f}s")
print(f"Многопоточность: {threaded_requests():.1f}s")
print(f"Асинхронно: {asyncio.run(async_requests()):.1f}s")

Ключевые моменты

  1. I/O операции — идеальный вариант (HTTP, БД, файлы, сеть)
  2. CPU-bound операции — используй многопроцессность
  3. Параллельная загрузка — асинхронность намного быстрее
  4. Масштабируемость — асинхронность справляется с тысячами соединений
  5. Не усложняй — синхронный код проще для простых случаев
Какие задачи хорошо подходят для асинхронного выполнения? | PrepBro