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

Когда используется процесс?

1.2 Junior🔥 61 комментариев
#Другое

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

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

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

Когда использовать процессы (Process) в Python

Процессы используются для параллельного выполнения CPU-bound операций, когда нужна настоящая параллельность, а не просто переключение контекста. Каждый процесс имеет собственный интерпретатор Python и GIL.

Основные сценарии

1. CPU-bound вычисления

Это главная причина использования процессов:

from multiprocessing import Process, cpu_count
import time

def cpu_heavy_task(n):
    """Вычисления, которые требуют CPU"""
    total = 0
    for i in range(100_000_000):
        total += i ** 2
    return total

# Способ 1: ПОТОКИ (BAD — не работает параллельно)
import threading
import time

start = time.time()
threads = []
for i in range(4):
    t = threading.Thread(target=cpu_heavy_task, args=(i,))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

thread_time = time.time() - start
print(f"Threading: {thread_time:.2f}s")  # ~8s (последовательно)

# Способ 2: ПРОЦЕССЫ (GOOD — работает параллельно)
from concurrent.futures import ProcessPoolExecutor

start = time.time()
with ProcessPoolExecutor(max_workers=4) as executor:
    results = list(executor.map(cpu_heavy_task, range(4)))

process_time = time.time() - start
print(f"Multiprocessing: {process_time:.2f}s")  # ~2s (параллельно)

2. Data processing с большими объёмами

from multiprocessing import Pool
import numpy as np

def process_chunk(data_chunk):
    """Обработка одного куска данных"""
    return np.mean(data_chunk)

# Генерируем большие данные
data = np.random.rand(1_000_000)
chunks = np.array_split(data, 8)  # 8 кусков

# Распределяем обработку между процессами
with Pool(processes=4) as pool:
    results = pool.map(process_chunk, chunks)

print(f"Average: {np.mean(results)}")

3. Machine Learning тренировка

from multiprocessing import Pool
from sklearn.ensemble import RandomForestClassifier
import numpy as np

def train_model(fold_data):
    X_train, y_train = fold_data
    model = RandomForestClassifier(n_jobs=-1)  # Использует все ядра
    model.fit(X_train, y_train)
    return model

# K-fold cross validation на нескольких процессах
kfolds = 5
with Pool(processes=4) as pool:
    models = pool.map(train_model, fold_data)

4. Обработка файлов

from multiprocessing import Pool
import os
import glob

def process_file(filepath):
    """Обработка одного файла"""
    with open(filepath, r) as f:
        content = f.read()
    # Тяжёлая обработка
    return len(content)

files = glob.glob("/data/*.txt")

with Pool(processes=8) as pool:
    sizes = pool.map(process_file, files)

print(f"Total: {sum(sizes)} bytes")

Варианты использования процессов

Pool vs Process

# Pool — удобнее для множественных задач
from multiprocessing import Pool

with Pool(processes=4) as pool:
    results = pool.map(func, data_list)

# Process — точнее контролируем
from multiprocessing import Process

proc = Process(target=func, args=(arg1, arg2))
proc.start()
proc.join()
print(proc.exitcode)  # 0 if success

ProcessPoolExecutor — современный стиль

from concurrent.futures import ProcessPoolExecutor

with ProcessPoolExecutor(max_workers=4) as executor:
    # Отправляем задачи
    futures = [executor.submit(task, i) for i in range(100)]
    
    # Получаем результаты по мере выполнения
    for future in concurrent.futures.as_completed(futures):
        result = future.result()
        print(result)

Обмен данными между процессами

Queue — безопасный обмен

from multiprocessing import Process, Queue

def worker(queue):
    queue.put("Hello from process")

queue = Queue()
proc = Process(target=worker, args=(queue,))
proc.start()
proc.join()

result = queue.get()
print(result)  # Hello from process

Pipe — двусторонняя коммуникация

from multiprocessing import Process, Pipe

def worker(conn):
    conn.send("Hello")
    msg = conn.recv()
    conn.close()

parent_conn, child_conn = Pipe()
proc = Process(target=worker, args=(child_conn,))
proc.start()

msg = parent_conn.recv()
print(msg)  # Hello

proc.join()

Manager — shared объекты

from multiprocessing import Process, Manager

def worker(shared_dict, shared_list):
    shared_dict["key"] = "value"
    shared_list.append(42)

with Manager() as manager:
    shared_dict = manager.dict()
    shared_list = manager.list()
    
    procs = [
        Process(target=worker, args=(shared_dict, shared_list))
        for _ in range(4)
    ]
    
    for p in procs:
        p.start()
    for p in procs:
        p.join()
    
    print(shared_dict)
    print(shared_list)

Когда НЕ использовать процессы

I/O-bound операции

# Плохо: процессы дорогие для I/O
import requests
from multiprocessing import Pool

def fetch_url(url):
    return requests.get(url).text

# Хорошо: асинхронность
import asyncio
import aiohttp

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

async def main():
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(url, session) for url in urls]
        results = await asyncio.gather(*tasks)

asyncio.run(main())

Малые объёмы данных

# Не стоит: overhead создания процесса > выигрыш
with Pool(2) as pool:
    result = pool.map(lambda x: x * 2, [1, 2, 3])

Сравнение: Threading vs Multiprocessing vs Async

ПараметрThreadingMultiprocessingAsyncio
CPU-bound❌ Плохо (GIL)✅ Отлично❌ Плохо
I/O-bound✅ Хорошо⚠️ Дорого✅ Лучше всего
MemoryЭкономноТяжелыйОчень экономно
Простота✅ Просто❌ Сложно (обмен данных)⚠️ Async/await
ScalabilityДо ~100 потоковДо ~100 процессовДо 10k+ корутин

Лучшие практики

# 1. Используй ProcessPoolExecutor для чистоты кода
from concurrent.futures import ProcessPoolExecutor

with ProcessPoolExecutor() as executor:
    futures = executor.map(func, data)

# 2. Избегай обмена большими данными
# (процессы используют pickle для сериализации)

# 3. Кол-во процессов = кол-во ядер CPU
import os
workers = os.cpu_count()

# 4. Используй if __name__ == "__main__":
if __name__ == "__main__":
    process = Process(target=worker)
    process.start()

Резюме

Используй процессы для:

  • CPU-bound вычисления (основное применение)
  • Machine Learning тренировка
  • Обработка больших объёмов данных
  • Когда нужна настоящая параллельность (не GIL)

НЕ используй процессы для:

  • I/O операций (используй asyncio)
  • Малых объёмов данных (overhead велик)
  • Частого обмена данными (используй потоки)