multiprocessing
для обхода GIL можно, поскольку он запускает процессы, а не потоки. Каждый процесс имеет свой собственный интерпретатор Python и, следовательно, свой собственный GIL. Это позволяет распараллеливать CPU-bound задачи между несколькими ядрами, избегая ограничений GIL, который позволяет только одному потоку в одном процессе выполнять Python-код в каждый момент времени. Вместо потоков (threading) используются процессы, обменивающиеся данными через очереди (queues) или разделяемую память (shared memory).
GIL (Global Interpreter Lock) в CPython, стандартной реализации Python, позволяет только одному потоку выполнять байт-код Python в один момент времени. Это ограничивает возможности распараллеливания для потоко-зависимых задач, особенно тех, которые интенсивно используют CPU.
Модуль multiprocessing
обходит ограничение GIL, используя процессы вместо потоков. Каждый процесс имеет свой собственный интерпретатор Python и, соответственно, свою собственную память. Это позволяет полноценно распараллеливать CPU-bound задачи, поскольку процессы могут выполняться одновременно на разных ядрах CPU.
Вот как можно использовать multiprocessing
для обхода GIL:
multiprocessing
.Process
, каждый из которых будет выполнять определенную функцию. При создании процесса, передайте целевую функцию (target
) и, опционально, аргументы (args
) этой функции.start()
для каждого объекта Process
.join()
для каждого процесса, чтобы дождаться завершения его работы. Это гарантирует, что основная программа не завершится до завершения всех дочерних процессов.Пример:
import multiprocessing
import time
def cpu_bound_task(number):
"""Выполняет CPU-bound задачу (простое возведение в степень)."""
start = time.time()
result = sum(i * i for i in range(number))
end = time.time()
print(f"Task {number} took {end - start:.4f} seconds")
return result
if __name__ == '__main__':
numbers = [10_000_000 + x for x in range(5)]
processes = []
# Создание и запуск процессов
start_time = time.time()
for number in numbers:
p = multiprocessing.Process(target=cpu_bound_task, args=(number,))
processes.append(p)
p.start()
# Ожидание завершения процессов
for p in processes:
p.join()
end_time = time.time()
print(f"Total time with multiprocessing: {end_time - start_time:.4f} seconds")
Важно:
multiprocessing
наиболее эффективен для относительно долго выполняющихся CPU-bound задач. Если задача очень короткая, затраты на создание процесса могут перевесить выгоду от распараллеливания.multiprocessing.Queue
, multiprocessing.Pipe
или совместно используемую память (multiprocessing.Value
, multiprocessing.Array
). Следует учитывать, что операции обмена данными также могут создавать накладные расходы.pickle
).multiprocessing
хорошо работает на большинстве операционных систем, включая Linux, macOS и Windows.В заключение, multiprocessing
предоставляет эффективный способ обойти ограничение GIL и распараллелить CPU-bound задачи, используя несколько процессов. Однако, важно учитывать накладные расходы, связанные с управлением процессами и обменом данными, чтобы убедиться, что распараллеливание действительно улучшает производительность.