Какие знаешь способы мультипроцессорного выполнения задач?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Способы мультипроцессорного выполнения задач в Python
В Python существует несколько подходов для параллельного выполнения работ на нескольких процессорных ядрах. Каждый метод имеет свои особенности и область применения.
1. Модуль multiprocessing
Самый прямой способ обхода GIL (Global Interpreter Lock). Создаёт отдельные процессы Python с независимыми интерпретаторами.
from multiprocessing import Process, Pool
import time
def worker(name, delay):
time.sleep(delay)
print(f"Worker {name} finished")
# Создание процесса
p = Process(target=worker, args=("A", 2))
p.start()
p.join()
# Pool для управления несколькими процессами
with Pool(processes=4) as pool:
results = pool.map(worker, [("B", 1), ("C", 2)])
Плюсы: истинный параллелизм, обход GIL, хорошо для CPU-bound задач. Минусы: высокие накладные расходы на создание процесса, сложность обмена данными.
2. Модуль threading
Потоки внутри одного процесса с общей памятью.
from threading import Thread
import time
def threaded_worker(name):
time.sleep(1)
print(f"Thread {name} done")
threads = [Thread(target=threaded_worker, args=(f"T{i}",)) for i in range(4)]
for t in threads:
t.start()
for t in threads:
t.join()
Плюсы: легко создавать, разделяют память, подходят для I/O-bound задач. Минусы: GIL ограничивает параллелизм CPU, нужна синхронизация.
3. asyncio
Асинхронное программирование для I/O-bound операций на одном потоке.
import asyncio
async def async_task(name, delay):
await asyncio.sleep(delay)
print(f"Task {name} done")
async def main():
await asyncio.gather(
async_task("A", 1),
async_task("B", 2),
async_task("C", 1)
)
asyncio.run(main())
Плюсы: очень эффективно для I/O, минимум ресурсов, просто масштабируется. Минусы: не работает с CPU-bound, требует async-compatible библиотек.
4. concurrent.futures
Высокоуровневый интерфейс для параллельной работы.
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
def cpu_intensive(n):
return sum(i*i for i in range(n))
# Для CPU-bound
with ProcessPoolExecutor(max_workers=4) as executor:
results = list(executor.map(cpu_intensive, [10**7, 10**7, 10**7]))
# Для I/O-bound
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(io_task, i) for i in range(10)]
results = [f.result() for f in futures]
Плюсы: простой API, flexibility в выборе executor'а. Минусы: меньше контроля чем multiprocessing/threading.
5. Распределённые системы
Для действительно крупной масштабируемости используют Celery, RQ, Dask.
from celery import Celery
app = Celery("tasks")
@app.task
def add(x, y):
return x + y
result = add.delay(4, 6) # Отправить на worker
Когда что использовать
- CPU-bound (вычисления): multiprocessing или ProcessPoolExecutor
- I/O-bound (сеть, файлы): asyncio или ThreadPoolExecutor
- Масштабирование: Celery, RQ, Dask
- Простота: concurrent.futures
Выбор зависит от характера задач, количества вычислений и требований к масштабируемости.