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

Какие используешь виды многозадачности в Python?

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

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

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

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

Виды многозадачности в Python

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

Основные виды многозадачности

1. Threading (потоки)

Многопоточность в Python использует ОС потоки, но ограничена GIL (Global Interpreter Lock).

import threading
import time

def worker(name):
    for i in range(3):
        print(f"{name}: {i}")
        time.sleep(1)

# Создание и запуск потока
thread = threading.Thread(target=worker, args=("Worker-1",))
thread.start()
thread.join()  # Ожидание завершения

# Несколько потоков
threads = []
for i in range(5):
    t = threading.Thread(target=worker, args=(f"Thread-{i}",))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

Плюсы:

  • Простая синтаксис
  • Подходит для I/O-bound операций (сеть, диск, БД)
  • Встроенный механизм синхронизации (Lock, Event, Condition)

Минусы:

  • GIL блокирует параллельное выполнение на CPU
  • Для CPU-bound операций неэффективно
  • Сложность с отладкой race conditions

Когда использовать: веб-скрепинг, обработка запросов, работа с базами данных.

2. Multiprocessing (процессы)

Использует отдельные процессы ОС, избегает GIL.

import multiprocessing
import os

def worker(name):
    print(f"{name}: PID {os.getpid()}")
    return name * 2

if __name__ == "__main__":
    with multiprocessing.Pool(processes=4) as pool:
        results = pool.map(worker, ["A", "B", "C", "D"])
        print(results)  # ['AA', 'BB', 'CC', 'DD']

# Или явное создание процессов
processes = []
for i in range(4):
    p = multiprocessing.Process(target=worker, args=(f"P-{i}",))
    processes.append(p)
    p.start()

for p in processes:
    p.join()

Плюсы:

  • Истинный параллелизм для CPU-bound операций
  • Каждый процесс имеет свой GIL
  • Идеально для обработки больших данных

Минусы:

  • Высокие затраты памяти (каждый процесс отдельный интерпретатор Python)
  • Медленнее потоков для I/O операций
  • Сложнее обмениваться данными между процессами

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

3. AsyncIO (асинхронное программирование)

Использует single-threaded event loop для управления множеством операций.

import asyncio
import aiohttp

async def fetch_url(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = [
        "https://example.com/1",
        "https://example.com/2",
        "https://example.com/3",
    ]
    
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        return results

# Запуск асинхронного кода
results = asyncio.run(main())

Плюсы:

  • Минимальные затраты памяти (single thread)
  • Очень быстро для I/O операций
  • Отличная масштабируемость (тысячи одновременных операций)
  • Нет race conditions (все в одном потоке)

Минусы:

  • Все должно быть асинхронным (async/await синтаксис)
  • Сложнее писать и отлаживать
  • Не подходит для CPU-bound операций

Когда использовать: веб-приложения (FastAPI, aiohttp), микросервисы, IoT.

Сравнение производительности

# 10 операций по 1 секунде каждая

# Threading: примерно 2-3 секунды (параллельно, но медленнее)
# Multiprocessing: примерно 5+ секунд (параллельно, но много overhead)
# AsyncIO: примерно 1-2 секунды (конкурентно, очень быстро)

Таблица сравнения

АспектThreadingMultiprocessingAsyncIO
GILДа (блокирует)Нет (отдельный)Нет (single-thread)
CPU-boundПлохоОтличноПлохо
I/O-boundХорошоПлохоОтлично
ПамятьСредняяВысокаяНизкая
ПростотаВысокаяСредняяНизкая
Тысячи операцийНетНетДа
Race conditionsВозможныНетНет

Практические примеры

Загрузка из 100 URL-ов

# ✅ AsyncIO (лучший выбор)
import asyncio
import aiohttp

async def load_urls():
    async with aiohttp.ClientSession() as session:
        tasks = [
            session.get(f"https://api.example.com/{i}")
            for i in range(100)
        ]
        await asyncio.gather(*tasks)

Обработка 1GB файла

# ✅ Multiprocessing (лучший выбор)
import multiprocessing

def process_chunk(chunk):
    return sum(chunk)

with multiprocessing.Pool() as pool:
    chunks = load_chunks("big_file.dat")
    results = pool.map(process_chunk, chunks)

Обработка HTTP запросов в веб-сервере

# ✅ Threading (с пулом потоков)
from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor(max_workers=10) as executor:
    executor.submit(handle_request, request)

Как выбрать правильный инструмент?

Начни с вопроса: Операция CPU-bound или I/O-bound?

CPU-bound (вычисления, обработка данных)?
└─> Multiprocessing (или Cython, NumPy)

I/O-bound (сеть, диск, БД)?
├─> Много операций (1000+)?
│   └─> AsyncIO (если поддерживается)
└─> Мало операций (< 100)?
    └─> Threading (проще)

GIL и его влияние

GIL (Global Interpreter Lock) - это мьютекс, который позволяет только одному потоку выполнять Python код одновременно.

# ❌ Threading для CPU-bound - медленнее чем single-thread!
import threading
import time

def cpu_bound():
    total = 0
    for i in range(50_000_000):
        total += i
    return total

# Single thread: ~2 секунды
start = time.time()
cpu_bound()
print(f"Single: {time.time() - start:.2f}s")

# 2 threads: ~4+ секунды (медленнее!)
threads = []
start = time.time()
for _ in range(2):
    t = threading.Thread(target=cpu_bound)
    threads.append(t)
    t.start()
for t in threads:
    t.join()
print(f"Threading: {time.time() - start:.2f}s")

# ✅ Multiprocessing: ~1.5 секунды (в два раза быстрее)

Современный подход в 2024-2025

Рекомендация для новых проектов:

  1. FastAPI + AsyncIO - для веб-приложений (99% веб-сервисов)
  2. multiprocessing.Pool - для batch обработки
  3. Threading - только для legacy кода
# Современный FastAPI пример
from fastapi import FastAPI
import aiohttp

app = FastAPI()

@app.get("/fetch")
async def fetch_data():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://api.example.com") as resp:
            return await resp.json()

Итог

Выбирай правильный инструмент:

  • Threading: простые I/O операции
  • Multiprocessing: тяжелые вычисления
  • AsyncIO: высоконагруженные I/O сервисы

Современный Python во многом из-за AsyncIO - это экосистема асинхронного программирования.

Какие используешь виды многозадачности в Python? | PrepBro