Какие задачи в Python целесообразно переносить с многопоточной модели на асинхронную

Ответ

На асинхронную модель стоит переносить задачи, связанные с ожиданием операций ввода-вывода (I/O-bound), так как это позволяет процессору не простаивать, а выполнять другую полезную работу, пока программа ожидает ответа.

Идеальные кандидаты для асинхронности:

  • Сетевые взаимодействия: HTTP-запросы к внешним API, работа с WebSocket, gRPC.
  • Операции с базами данных: Чтение и запись при использовании асинхронных драйверов (например, asyncpg для PostgreSQL).
  • Работа с файловой системой: Асинхронное чтение/запись файлов.

Задачи, не подходящие для асинхронности:

  • Вычислительно-интенсивные задачи (CPU-bound): Сложные математические расчеты, обработка изображений, шифрование. Такие задачи блокируют основной поток (event loop), сводя на нет все преимущества асинхронности. Для них лучше использовать многопроцессорность (multiprocessing).

Пример: Асинхронный HTTP-запрос

import aiohttp
import asyncio

async def fetch_data(url):
    # Сессия создается один раз для множества запросов
    async with aiohttp.ClientSession() as session:
        # Программа не блокируется, а "ожидает" ответа от сервера
        async with session.get(url) as response:
            print(f"Status: {response.status}")
            return await response.text()

# Запуск асинхронной функции
# asyncio.run(fetch_data('https://api.github.com'))

Ответ 18+ 🔞

Слушай, а вот этот твой асинхронный пиздец — это ж не просто так, чтобы код красивый был. Это чтобы комп не стоял как идиот, пока какой-нибудь удалённый сервер думает, как ему твой запрос послать нахуй.

Короче, если задача I/O-bound — то есть она в основном ждёт, пока кто-то другой соизволит ответить (сеть, диск, база данных), — то это идеальный кандидат. Процессор в это время может другие дела делать, а не срать кирпичами.

Что можно и нужно пихать в асинхронность:

  • Сеть: Все эти твои запросы к API, вебсокеты, gRPC. Пока один запрос летит до Гитхаба и обратно, можно ещё двадцать отправить.
  • Базы данных: Но только если драйвер асинхронный, а не старый блокирующий кусок говна. asyncpg — да, стандартный psycopg2 — нет, он всё затормозит.
  • Файлы: Чтение-запись, особенно если файлы большие или их много.

А что НЕЛЬЗЯ, блядь:

  • CPU-bound задачи: Всё, где процессор должен пахать без остановки — сложная математика, шифрование, рендеринг. Такая штука заблокирует весь твой event loop, и будет он тупить, как Герасим, когда ему объясняли, зачем топить Муму. Для этого есть multiprocessing — пусть другие ядра процессора страдают.

Вот, смотри, как это выглядит на практике, чтобы не быть теоретическим пиздаболом:

import aiohttp
import asyncio

async def fetch_data(url):
    # Сессия создается один раз для множества запросов
    async with aiohttp.ClientSession() as session:
        # Программа не блокируется, а "ожидает" ответа от сервера
        async with session.get(url) as response:
            print(f"Status: {response.status}")
            return await response.text()

# Запуск асинхронной функции
# asyncio.run(fetch_data('https://api.github.com'))

Видишь? Пока session.get ждёт ответа от сервера, твоя программа может переключиться и делать что-то ещё. Красота, ёпта! А не как раньше — послал запрос и сиди, хуем груши околачиваешь, пока ответ не прилетит.