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

В чём разница между мультипоточностью и мультипроцессорностью?

2.0 Middle🔥 171 комментариев
#Python

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

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

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

Мультипоточность (Multithreading) и мультипроцессорность (Multiprocessing)

Оба подхода используются для параллельного выполнения кода, но имеют принципиальные различия в архитектуре, использовании ресурсов и применении в Data Engineer задачах.

Основные различия

АспектМультипоточностьМультипроцессорность
ПроцессНитиями одного процессаОтдельные процессы ОС
ПамятьОбщая памяти между потокамиИзолированная память каждого процесса
Переключение контекстаБыстро (тяжелого процесса нет)Медленнее (полное переключение контекста)
GIL (Python)Присутствует, блокирует параллелизмОтсутствует, истинный параллелизм
OverheadНизкий (потоки легче)Высокий (процессы тяжелее)
СинхронизацияТребуется (locks, semaphores)Меньше требуется
Использование ядер CPUНеэффективно (GIL в Python)Эффективно, использует все ядра
БезопасностьRace conditions возможныМеньше проблем с доступом данных

Мультипоточность (Multithreading)

Определение: Несколько потоков выполняются в контексте одного процесса, разделяя одно адресное пространство памяти и ресурсы.

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

  • Легче и быстрее создать поток (меньше overhead)
  • Быстрое переключение контекста
  • Лёгкий обмен данными (общая память)
  • Меньше затрат на ресурсы системы

Недостатки:

  • GIL (Global Interpreter Lock) в Python — только один поток может выполнять Python код одновременно
  • Требуется тщательная синхронизация доступа к данным
  • Race conditions и deadlocks
  • Для CPU-bound задач неэффективна (только I/O bound)

Пример в Python:

import threading
import time

def fetch_data(url):
    # I/O операция (сетевой запрос)
    print(f"Fetching {url}")
    time.sleep(2)  # Имитация сетевого запроса
    print(f"Done {url}")

# Создаём потоки для I/O операций
threads = []
for i in range(3):
    t = threading.Thread(target=fetch_data, args=(f"url_{i}",))
    threads.append(t)
    t.start()

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

Этот код эффективен, потому что пока один поток ждёт I/O, другие выполняют полезную работу.

Мультипроцессорность (Multiprocessing)

Определение: Несколько отдельных процессов ОС выполняются параллельно, каждый с собственным адресным пространством памяти и ресурсами.

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

  • Истинный параллелизм на многоядерных системах
  • Обходит GIL в Python
  • Каждый процесс изолирован (безопаснее)
  • Отличное для CPU-bound задач
  • Если один процесс упадет, другие продолжат работу

Недостатки:

  • Больше overhead при создании процесса
  • Медленнее переключение контекста
  • Сложнее обмен данными между процессами (требует serialization)
  • Требует больше памяти (каждый процесс имеет свою копию данных)
  • Синхронизация сложнее

Пример в Python:

from multiprocessing import Pool
import time

def cpu_intensive_task(n):
    # CPU-bound операция
    total = 0
    for i in range(n):
        total += i ** 2
    return total

# Используем Pool процессов
with Pool(processes=4) as pool:
    results = pool.map(cpu_intensive_task, [10**7, 10**7, 10**7, 10**7])
    print(results)

Этот код использует все 4 ядра CPU одновременно, что невозможно с потоками в Python.

Применение в Data Engineering

Когда использовать мультипоточность:

  • I/O операции: загрузка данных по сети, чтение/запись файлов
  • API requests: множественные HTTP запросы к external сервисам
  • Database queries: асинхронные запросы к БД
  • Пример: парсинг 1000 URL одновременно
import threading
import requests

def download_data(url):
    response = requests.get(url)
    return response.json()

urls = [f"https://api.example.com/data/{i}" for i in range(100)]
threads = [threading.Thread(target=download_data, args=(url,)) for url in urls]

Когда использовать мультипроцессорность:

  • CPU-bound операции: обработка данных, вычисления, трансформации
  • Big Data processing: Spark, Dask используют multiprocessing
  • Машинное обучение: обучение моделей на больших наборах данных
  • Пример: параллельная обработка больших файлов
from multiprocessing import Pool
import pandas as pd

def process_chunk(chunk):
    # Тяжёлая обработка данных
    return chunk.groupby("category").agg({"value": "sum"})

data = pd.read_csv("large_file.csv")
chunks = [data[i:i+10000] for i in range(0, len(data), 10000)]

with Pool(processes=8) as pool:
    results = pool.map(process_chunk, chunks)

GIL (Global Interpreter Lock) в Python

GIL — ключевая причина различий для Python-разработчиков:

import threading
import time

# CPU-bound задача
def cpu_work(n):
    total = 0
    for i in range(n):
        total += i
    return total

n = 100_000_000

# С потоками: GIL блокирует параллелизм
start = time.time()
threads = [threading.Thread(target=cpu_work, args=(n,)) for _ in range(2)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print(f"Threading: {time.time() - start:.2f}s")  # ~2x медленнее

# С процессами: истинный параллелизм
from multiprocessing import Process
start = time.time()
processes = [Process(target=cpu_work, args=(n,)) for _ in range(2)]
for p in processes:
    p.start()
for p in processes:
    p.join()
print(f"Multiprocessing: {time.time() - start:.2f}s")  # ~2x быстрее

Рекомендации для Data Engineer

  1. I/O операции → используй мультипоточность или asyncio
  2. CPU-bound задачи → используй мультипроцессорность
  3. Spark/Dask → внутренне используют мультипроцессорность
  4. Микросервисы API → asyncio + aiohttp (асинхронность вместо потоков)
  5. Всегда профилируй — используй cProfile или line_profiler
  6. Масштабируемость → распределённые системы (Spark, Hadoop) лучше, чем мультипроцессинг на одной машине