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 в настоящее время не проверяет это.