Я пытался использовать пакет многопроцессорной обработки python для ускорения некоторых физических симуляций, которые я выполняю, используя преимущества нескольких ядер моего компьютера.
Я заметил, что когда я запускаю свою симуляцию, используется не более 3 из 12 ядер. Фактически, когда я запускаю симуляцию, она сначала использует 3 ядра, а затем, через некоторое время, переходит на 1 ядро. Иногда с самого начала используются только одно или два ядра. Я не мог понять, почему (я в основном ничего не меняю, кроме закрытия нескольких окон терминала (без каких-либо активных процессов)). (ОС - Red Hat Enterprise Linux 6.0, версия Python - 2.6.5.)
Я экспериментировал, варьируя количество фрагментов (от 2 до 120), на которые разбивается работа (то есть количество создаваемых процессов), но это, похоже, не имело никакого эффекта.
Я поискал информацию об этой проблеме в Интернете и прочитал большинство связанных вопросов на этом сайте (например, один , два), но не смог найти решения.
(Изменить: я просто попытался запустить код под Windows 7, и он правильно использует все доступные ядра. Я все же хочу исправить это для RHEL.)
Вот мой код (без учета физики):
from multiprocessing import Queue, Process, current_process
def f(q,start,end): #a dummy function to be passed as target to Process
q.put(mc_sim(start,end))
def mc_sim(start,end): #this is where the 'physics' is
p=current_process()
print "starting", p.name, p.pid
sum_=0
for i in xrange(start,end):
sum_+=i
print "exiting", p.name, p.pid
return sum_
def main():
NP=0 #number of processes
total_steps=10**8
chunk=total_steps/10
start=0
queue=Queue()
subprocesses=[]
while start<total_steps:
p=Process(target=f,args=(queue,start,start+chunk))
NP+=1
print 'delegated %s:%s to subprocess %s' % (start, start+chunk, NP)
p.start()
start+=chunk
subprocesses.append(p)
total=0
for i in xrange(NP):
total+=queue.get()
print "total is", total
#two lines for consistency check:
# alt_total=mc_sim(0,total_steps)
# print "alternative total is", alt_total
while subprocesses:
subprocesses.pop().join()
if __name__=='__main__':
main()
(Фактически код основан на ответе Алекса Мартелли здесь.)
Изменить 2: в конце концов проблема разрешилась сама собой, и я не понял, как это сделать. Я не менял код и не слышал об изменении чего-либо, связанного с ОС. Несмотря на это, теперь при запуске кода используются все ядра. Возможно, проблема возникнет позже, но пока я предпочитаю не исследовать ее дальше, поскольку она работает. Всем спасибо за помощь.
mc_sim
реализован на чистом питоне, а не в коде C, отличном от Python, то вы, вероятно, столкнетесь с GIL (глобальная блокировка интерпретатора). Если вы все же зашли на какой-нибудь C или Cython, который не требует GIL, вам необходимо убедиться, что подпрограмма правильно помечена как, например,cdef void func(int a) nogil
(во всяком случае, именно так вы это делаете для Cython.) - person tehwalrus   schedule 03.10.2012while subprocesses: ...
), прежде чем вычислять окончательную сумму (две строки, начинающиеся сfor i in range(NP):
)? Я просто попробовал это, и, похоже, это не имеет значения. - person the.real.gruycho   schedule 03.10.2012multiprocessing
только потому, что в документации сказано, что это не так. не использую GIL. Я не могу найти проблему в вашем коде, поэтому, если вы тоже не найдете ее, я предлагаю вам взглянуть на параллельный модуль Python. Это легко, быстро, не использует GIL и, вероятно, может вам помочь (опять же, если вы не найдете проблемы). - person aga   schedule 03.10.2012multiprocessing
гарантирует только то, что вы будете работать с несколькими процессами. Операционная служба должна распределять эти процессы между доступными ядрами, AFAIK. - person mpenkov   schedule 03.10.2012multiprocessing.current_process()
, чтобы проверить, какие процессы запускаются (я отредактирую код выше, чтобы показать это). Все процессы запускались немедленно, но, тем не менее, только несколько ядер (максимум 3, но иногда 1 или 2) были активными. Через несколько часов я запустил тот же код, и все 12 ядер были использованы. Затем я переключил компьютер в спящий режим и сразу же снова включил, а затем снова запустил код. На этот раз снова использовалось лишь несколько ядер. Сбивает с толку. - person the.real.gruycho   schedule 04.10.2012range(start,end)
может использовать много памяти, еслиend-start
- большое число. Чтобы исправить это, можно использоватьwhile (start<end): ... start+=1
. Я пробовал это, но все же использовалось лишь несколько ядер. - person the.real.gruycho   schedule 04.10.2012multiprocessing.Queue
в Python 2.6 на RHEL 5 или 6. Я отлично использовал его в нескольких проектах. @Tropcho: Конечно, вы не должны использоватьrange
в Python 2.x - вместо этого используйтеxrange
. При использовании многих процессов используйтеps
илиtop
для проверки их типичного состояния выполнения. - person Acumenus   schedule 04.10.2012