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

Какой тип конкурентность нужно использовать для быстрого выполнения CPU-bound задач?

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

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

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

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

Конкурентность для CPU-bound задач

Для быстрого выполнения CPU-bound задач в Python нужно использовать multiprocessing, а не threading или asyncio.

Почему multiprocessing?

Проблема в том, что Python имеет Global Interpreter Lock (GIL), который не позволяет нескольким потокам выполняться параллельно в одном процессе. Threading подходит только для I/O-bound операций (сетевые запросы, работа с файлами), где поток может отпустить GIL во время ожидания.

Для CPU-bound работы (вычисления, обработка данных) нужны отдельные процессы с собственными интерпретаторами Python и собственными GIL.

Пример с multiprocessing

from multiprocessing import Pool
import time

def cpu_intensive_task(n):
    """Тяжелые вычисления"""
    total = 0
    for i in range(n):
        total += i ** 2
    return total

def main():
    # Используем столько процессов, сколько ядер в системе
    with Pool() as pool:
        # Распределяем работу между процессами
        results = pool.map(cpu_intensive_task, [10000000] * 4)
    print(results)

if __name__ == "__main__":
    main()

Альтернативы

ProcessPoolExecutor — более современный способ:

from concurrent.futures import ProcessPoolExecutor

def main():
    with ProcessPoolExecutor(max_workers=4) as executor:
        # Отправляем задачи в пул процессов
        futures = [executor.submit(cpu_intensive_task, 10000000) for _ in range(4)]
        results = [f.result() for f in futures]
    print(results)

Важные моменты

  1. Количество рабочих: обычно выбирают столько, сколько ядер в CPU (os.cpu_count())
  2. Overhead коммуникации: multiprocessing имеет оверхед на передачу данных между процессами, так что имеет смысл только для действительно тяжелых задач
  3. Pickle сериализация: все аргументы должны быть пиклируемы
  4. если задача очень легкая: оверхед может не стоить выигрыша

Когда использовать что?

  • Threading: I/O-bound (сетевые запросы, файлы, БД)
  • asyncio: I/O-bound с большим числом одновременных операций
  • multiprocessing: CPU-bound вычисления
# Неправильно для CPU-bound
from threading import Thread
threads = [Thread(target=cpu_task) for _ in range(4)]
# GIL не даст реальный параллелизм!

# Правильно для CPU-bound
from multiprocessing import Process
processes = [Process(target=cpu_task) for _ in range(4)]
# Каждый процесс имеет свой GIL — реальный параллелизм

Вывод: для CPU-bound задач всегда используй multiprocessing или ProcessPoolExecutor, это единственный способ получить реальный параллелизм в Python.