Python использовать все ядра

Как получить доступ ко всем ядрам компьютера для вычисления в python script?

У меня есть python script, который должен принимать много перестановок большого набора данных, оценивать каждую перестановку и сохранять только самые высокие скоринговые перестановки. Набор данных настолько велик, что для этого script требуется почти 3 дня.

Когда я проверяю свои системные ресурсы в окнах, используется только 12% моего процессора, и только 4 из 8 ядер работают вообще. Даже если я поставил процесс python.exe с наивысшим приоритетом, это не изменится.

Мое предположение заключается в том, что выделение большего количества использования ЦП для запуска script может заставить его работать быстрее, но моя конечная цель – сократить время выполнения, по крайней мере, на половину. Есть ли модуль python или какой-то код, который мог бы мне помочь? В стороне это звучит как проблема, которая может выиграть от более разумного алгоритма?

Есть несколько способов сделать это, но проверьте multiprocessing модуль. Это стандартный библиотечный модуль для создания нескольких процессов, подобных потокам, но без ограничений GIL.

Вы также можете изучить отличную библиотеку Celery. Это распределенная очередь задач и имеет множество замечательных функций. Его довольно простая установка и легко начать работу.

Я могу ответить на HOW-TO с помощью простого примера кода. Пока это выполняется, запустите /bin/top и посмотрите ваши процессы. Просто сделать. Заметьте, я даже включил, как очистить после этого от прерывания клавиатуры – без этого ваши подпроцессы будут продолжать работать, и вам придется убивать их вручную.

from multiprocessing import Process import traceback import logging import time class AllDoneException(Exception): pass class Dum(object): def __init__(self): self.numProcesses = 10 self.logger = logging.getLogger() self.logger.setLevel(logging.INFO) self.logger.addHandler(logging.StreamHandler()) def myRoutineHere(self, processNumber): print "I'm in process number %d" % (processNumber) time.sleep(10) # optional: raise AllDoneException def myRoutine(self): plist = [] try: for pnum in range(0, self.numProcesses): p = Process(target=self.myRoutineHere, args=(pnum, )) p.start() plist.append(p) while 1: isAliveList = [p.is_alive() for p in plist] if not True in isAliveList: break time.sleep(1) except KeyboardInterrupt: self.logger.warning("Caught keyboard interrupt, exiting.") except AllDoneException: self.logger.warning("Caught AllDoneException, Exiting normally.") except: self.logger.warning("Caught Exception, exiting: %s" % (traceback.format_exc())) for p in plist: p.terminate() d = Dum() d.myRoutine() 

Вы должны создавать новые процессы вместо потоков, чтобы использовать ядра в своем процессоре. Мое общее правило – это один процесс на ядро. Таким образом, вы разбиваете пространство ввода проблем на количество доступных ядер, каждый процесс становится частью проблемного пространства.

Читайте также:  Java hibernate postgresql gradle

Multiprocessing лучше всего подходит для этого. Вы также можете использовать Parallel Python.

Очень поздно вечеринке – но помимо использования мультипроцессорного модуля, как сказал reptilicus, также обязательно установите “близость”.

Некоторые модули python участвуют в этом, эффективно уменьшая количество ядер, доступных для Python:

Из-за блокировки Global Interpreter один процесс Python не может использовать преимущества нескольких ядер. Но если вы каким-либо образом распараллеливаете свою проблему (что вам следует делать в любом случае), вы можете использовать multiprocessing для создания как можно большего числа процессов Python, поскольку у вас есть ядра и обрабатывать эти данные в каждом подпроцессе.

Источник

Как работать с многоядерными процессорами в Python?

Собственно правильно ли я понимаю, что это вообще невозможно, так как из-за GIL в Python все потоки все равно будут делаться последовательно одним процессором? Актуально ли это для Python 3.4? Как обойти (писать код на C)?

https://docs.python.org/2/library/multiprocessing.html — единственный известный мне способ утилизровать несколько ядер на питоне. GIL есть в обоих ветках питона, обойти никак (вроде, если я не ошибаюсь, написав экстеншн на С, Вы все равно будете вынуждены запускать его в тех же условиях).

Т.е. для использования нескольких процессоров необходимо ветвить процессы, а не потоки? Модули subprocess и threading не подходят?

iegor: subprocess тоже позволит использовать несколько ядер процессора, но он используется для исполнения исполняемых файлов + имеет блокирующее апи (мультипроцессинг же позволяет выполнить определенную функцию, например, что куда удобней именно для целей распараллеливания). Т. е. если Вы в своем процессе вызываете сабпроцесс, то текущий процесс будет заблокирован ожиданием ответа, но в данном случае вам как раз поможет threading или какой-нибуль gevent. Вообще это довольно сложная тема. Вкратце попытаюсь объяснить: GIL не настолько портит жизнь как Вам кажется. К примеру, у вас есть задача спарсить 100 сайтов. Вы в главном потоке создаете через threading 4 потока и в каждый из них отправляете по 25 сайтов на парсинг. Управление получает первый поток — он вызывает какой-нибудь requests.get, который является блокирующей операцией. Соответственно текущий поток начинает ждать ответа. GIL в этот момент освобождает лок и другой поток начинает свое выполнение. И так повторяется для каждого потока. Получается пока происходит блокирующая операция в одном потоке, второй может работать. Естественно все это происходит только на одном ядре и не является полноценным мултитридингом, но если писать аккуратно и вдумчиво, то на блокирующих операциях даже при GIL с threading можно получить прирост производительности. Ну а вообще примите как факт, что питон не умеет утилизировать многоядерные процессы и жизнь станет проще 🙂

Читайте также:  And operand in php

Sly_tom_cat

from time import time
from threading import Thread
from multiprocessing import Process

def count(n):
while n > 0:
n -= 1

startTime = time()
count(100000000)
count(100000000)
print(‘\nSequential execution time : %3.2f s.’%(time() — startTime))

startTime = time()
t1 = Thread(target=count, args=(100000000,))
t2 = Thread(target=count, args=(100000000,))
t1.start(); t2.start()
t1.join(); t2.join()
print(‘\nThreaded execution time : %3.2f s.’%(time() — startTime))

startTime = time()
p1 = Process(target=count, args=(100000000,))
p2 = Process(target=count, args=(100000000,))
p1.start(); p2.start()
p1.join(); p2.join()
print(‘\nMultiprocessed execution time : %3.2f s.’%(time() — startTime))

Sequential execution time : 6.83 s.

Threaded execution time : 11.37 s.

Multiprocessed execution time : 6.30 s.

Но допустим распараллеливание запросов к http серверу и в thread варианте даст огромный выигрыш.
Т.е. без учета специфики задачи — в многопоточность/многопроцессорность — лучше просто не соваться.

Источник

Оцените статью