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

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

1.7 Middle🔥 161 комментариев
#Асинхронность и многопоточность

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

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

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

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

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

1. Threading (многопоточность)

Многопоточность использует несколько потоков, работающих в рамках одного процесса. Все потоки делят одно адресное пространство.

import threading
import time

def worker(worker_id):
    """Функция, которая будет работать в отдельном потоке"""
    for i in range(3):
        print(f"Worker {worker_id}: iteration {i}")
        time.sleep(0.1)  # Имитация работы
    print(f"Worker {worker_id}: done")

# Создание и запуск потоков
threads = []
for i in range(3):
    thread = threading.Thread(target=worker, args=(i,))
    thread.start()
    threads.append(thread)

# Ожидание завершения всех потоков
for thread in threads:
    thread.join()

print("All threads completed")

Преимущества:

  • Простая синтаксис и понимание
  • Потоки легко создавать
  • Хорошо для I/O-bound операций (сетевые запросы, файловые операции)

Недостатки:

  • GIL (Global Interpreter Lock) — только один поток может выполнять Python код одновременно
  • Непригодна для CPU-bound операций
  • Сложна для отладки (race conditions, deadlocks)
  • Требует синхронизации (Lock, RLock, Semaphore)
import threading

# Проблема: race condition
counter = 0
lock = threading.Lock()

def increment():
    global counter
    with lock:  # Необходима блокировка для безопасности
        temp = counter
        temp += 1
        counter = temp

# Без lock возможна потеря обновлений!

2. Multiprocessing (многопроцессность)

Многопроцессность создает отдельные процессы с независимыми интерпретаторами Python. Каждый процесс имеет собственный GIL.

import multiprocessing
import time

def worker(worker_id):
    """Функция, выполняемая в отдельном процессе"""
    for i in range(3):
        print(f"Worker {worker_id} (PID {multiprocessing.current_process().pid}): iteration {i}")
        time.sleep(0.1)
    print(f"Worker {worker_id}: done")

if __name__ == "__main__":
    processes = []
    for i in range(3):
        process = multiprocessing.Process(target=worker, args=(i,))
        process.start()
        processes.append(process)
    
    # Ожидание завершения всех процессов
    for process in processes:
        process.join()
    
    print("All processes completed")

# Output:
# Worker 0 (PID 12345): iteration 0
# Worker 1 (PID 12346): iteration 0
# Worker 2 (PID 12347): iteration 0
# ...

Преимущества:

  • Избегает GIL — каждый процесс имеет собственный интерпретатор
  • Отлично для CPU-bound операций (математические вычисления, обработка данных)
  • Процессы полностью изолированы

Недостатки:

  • Дорого запускать (высокие затраты на память и инициализацию)
  • Обмен данными требует сериализации (pickle)
  • Более сложная синхронизация (Queue, Pipe)
import multiprocessing

def expensive_calculation(n):
    """CPU-bound операция"""
    return sum(i*i for i in range(n))

if __name__ == "__main__":
    with multiprocessing.Pool(4) as pool:
        # Параллельная обработка с 4 процессами
        results = pool.map(expensive_calculation, [1000000, 2000000, 3000000, 4000000])
    
    print(results)

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

Асинхронное программирование использует один поток, но обрабатывает множество задач асинхронно (cooperative multitasking). Когда одна задача ждет I/O, другая может выполняться.

import asyncio

async def worker(worker_id):
    """Асинхронная функция (корутина)"""
    for i in range(3):
        print(f"Worker {worker_id}: iteration {i}")
        await asyncio.sleep(0.1)  # await позволяет другим корутинам работать
    print(f"Worker {worker_id}: done")

async def main():
    # Создание и запуск 3 задач параллельно
    tasks = [worker(i) for i in range(3)]
    await asyncio.gather(*tasks)
    print("All tasks completed")

# Запуск async программы
asyncio.run(main())

# Output:
# Worker 0: iteration 0
# Worker 1: iteration 0
# Worker 2: iteration 0
# Worker 0: iteration 1
# ...

Преимущества:

  • Очень быстро и эффективно для I/O-bound операций
  • Один поток → нет race conditions
  • Меньше памяти, чем threading/multiprocessing
  • Отлично для high-concurrency (тысячи одновременных соединений)

Недостатки:

  • GIL все еще ограничивает CPU-bound операции
  • Требует async/await синтаксиса (не совместимо с обычным кодом)
  • Сложнее для начинающих
import asyncio
import aiohttp

async def fetch_url(session, url):
    """Асинхронный HTTP запрос"""
    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

# 3 сетевых запроса выполняются параллельно (не последовательно)
# Total time: ~1 second (вместо 3 секунд при последовательном выполнении)

Сравнительная таблица

СвойствоThreadingMultiprocessingAsyncio
Использование памятиСреднееВысокоеНизкое
CPU-boundНет (GIL)ДаНет (GIL)
I/O-boundДаДаДа (лучше всех)
ПростотаПростаяСредняяСредняя
Race conditionsРискНизкийНет
МасштабируемостьДо ~100 потоковДо ~1000 процессовДо ~10,000+ задач
СинхронизацияLock, ConditionQueue, PipeEvent, Lock

Практические примеры для выбора

Используй Threading для:

  • Веб-скрейпинг с небольшим количеством параллельных запросов
  • Работа с файловой системой
  • Создание простого многопоточного сервера

Используй Multiprocessing для:

  • Обработка больших массивов данных (machine learning)
  • Математические вычисления
  • Независимые задачи, которые не требуют частого взаимодействия

Используй Asyncio для:

  • Web фреймворки (FastAPI, aiohttp)
  • Микросервисы с множеством I/O операций
  • Чатботы (Telegram, Discord)
  • Real-time приложения (WebSockets)

Гибридный подход

import asyncio
import multiprocessing
from concurrent.futures import ProcessPoolExecutor

async def cpu_bound_task(n):
    """CPU-bound операция в отдельном процессе"""
    def calculate():
        return sum(i*i for i in range(n))
    
    loop = asyncio.get_event_loop()
    with ProcessPoolExecutor() as executor:
        result = await loop.run_in_executor(executor, calculate)
    return result

async def main():
    # Комбинируем asyncio для I/O и multiprocessing для CPU
    io_task = asyncio.sleep(1)
    cpu_task = cpu_bound_task(10000000)
    
    results = await asyncio.gather(io_task, cpu_task)
    print(results)

asyncio.run(main())

Python 3.13+ : asyncio improvements

В новых версиях Python asyncio получил серьезные оптимизации и теперь может конкурировать по производительности с Go и Rust для I/O-bound операций.