Какие используешь виды многозадачности в Python?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды многозадачности в 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 секунды (конкурентно, очень быстро)
Таблица сравнения
| Аспект | Threading | Multiprocessing | AsyncIO |
|---|---|---|---|
| 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
Рекомендация для новых проектов:
- FastAPI + AsyncIO - для веб-приложений (99% веб-сервисов)
- multiprocessing.Pool - для batch обработки
- 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 - это экосистема асинхронного программирования.