Глобальная блокировка интерпретатора (GIL)

Multiprocessing.Pool

На вопрос, как использовать потоки в Python, ответ прост: «Не используйте вместо этого процессы». Модуль многопроцессорной обработки позволяет создавать процессы с синтаксисом, аналогичным синтаксису создания потоков, но я предпочитаю использовать их удобный объект Pool.

Используя код , который Дэвид Бизли первым используется , чтобы показать опасность нитей против GIL , мы перепишем его с помощью multiprocessing.Pool :

Код Дэвида Бизли, который показал проблемы с GIL-потоками

 from threading import Thread
import time
def countdown(n):
    while n > 0:
        n -= 1

COUNT = 10000000

t1 = Thread(target=countdown,args=(COUNT/2,))
t2 = Thread(target=countdown,args=(COUNT/2,))
start = time.time()
t1.start();t2.start()
t1.join();t2.join()
end = time.time()
print end-start

 


Переписано с использованием мультипроцессинга.

Вместо создания потоков это создает новые процессы. Поскольку каждый процесс имеет свой собственный интерпретатор, коллизии GIL отсутствуют. multiprocessing.Pool откроет столько процессов, сколько имеется ядер на машине, хотя в приведенном выше примере потребуется только два. В реальном сценарии вы хотите, чтобы ваш список был как минимум такой же длины, как и процессоры на вашей машине. Пул будет запускать функцию, которую вы скажете ему запускать с каждым аргументом, вплоть до числа процессов, которые он создает. Когда функция завершится, все остальные функции в списке будут запущены в этом процессе.

Я обнаружил , что, даже используя with заявлением, если вы не близко и присоединиться к пулу, процессы продолжают существовать. Чтобы очистить ресурсы, я всегда закрываюсь и присоединяюсь к своим бассейнам.

Cython Nogil:

Cython является альтернативным интерпретатором Python. Он использует GIL, но позволяет отключить его. Смотрите их документации

В качестве примера, используя код , который Дэвид Бизли первым используется , чтобы показать опасность нитей против GIL , мы перепишем его с помощью nogil:

Код Дэвида Бизли, который показал проблемы с GIL-потоками

 from threading import Thread
import time
def countdown(n):
    while n > 0:
        n -= 1

COUNT = 10000000

t1 = Thread(target=countdown,args=(COUNT/2,))
t2 = Thread(target=countdown,args=(COUNT/2,))
start = time.time()
t1.start();t2.start()
t1.join();t2.join()
end = time.time()
print end-start

 

Переписано с использованием nogil (ТОЛЬКО РАБОТАЕТ НА ЦИФОНЕ):

 from threading import Thread
import time
def countdown(n):
    while n > 0:
        n -= 1

COUNT = 10000000

with nogil:
    t1 = Thread(target=countdown,args=(COUNT/2,))
    t2 = Thread(target=countdown,args=(COUNT/2,))
    start = time.time()
    t1.start();t2.start()
    t1.join();t2.join()

end = time.time()
print end-start

 

Это так просто, если вы используете Cython. Обратите внимание, что в документации сказано, что вы должны быть уверены, что не меняете объекты Python:

Код в теле оператора не должен каким-либо образом манипулировать объектами Python и не должен вызывать ничего, что манипулирует объектами Python без предварительного повторного получения GIL. Cython в настоящее время не проверяет это.