грубое распараллеливание с питоном с использованием многоядерных процессоров - PullRequest
0 голосов
/ 26 августа 2011

У меня есть программа на Python, в какой-то момент она вызывает внешнюю программу (foo).Эту внешнюю программу нужно запускать несколько раз.Точное число раз (num_pros) является переменным и зависит от ввода.Поскольку эта внешняя программа является самой трудоемкой частью моей программы на Python, я хотел бы использовать преимущества многоядерных процессоров для одновременного запуска нескольких экземпляров внешней программы.

Я пришел со следующим решением, которое учитывает, что num_pros априори неизвестен и что решение должно быть адаптировано к любому количеству ядер.

cores=2
proc_list=[]
for i in range(0,num_pros):
    proc=Popen(['foo'], stdin=PIPE)
    proc_list.append(proc)
    if i%cores == cores-1: 
        for process in proc_list:
            process.wait()

У меня два вопроса:

Есть лучшее (более эффективное или питонное) решение?

Этот код сокращает время выполнения только тогда, когда ядра реальны,Это аппаратная проблема?Или что-то, что можно исправить с помощью python?

Для пояснения второго вопроса приведу пример.В моей записной книжке (под управлением Linux) comnand 'cat / proc / cpuinfo |процессор grep |wc -l 'указывает на наличие 4 процессоров, если я использую в своем коде cores = 2, я получаю результаты в два раза быстрее (как и ожидалось), но при использовании core = 3 или core = 4 я получаю такую ​​же производительность, как и приядра = 2.У меня есть Intel Core I3 (2 ядра и 4 потока), поэтому я предполагаю, что проблема в том, что только 2 ядра являются реальными (я тестирую код на другом компьютере / процессоре, и получаю тот же результат, что полезны только реальные ядра).

Ответы [ 2 ]

0 голосов
/ 30 августа 2011

Простой способ: возьмите систему с N-ядрами, проведите несколько тестов, чтобы определить, сколько процессов вашему приложению необходимо выполнить с максимальной эффективностью. Вероятно, это будет около N, N + 1 или N + 2 процессов (например, при обычной сборке программного обеспечения make запуски документации часто предлагают установить -j в N + 1). Затем для рабочих запусков просто спросите пользователя или операционную систему о количестве физических ядер (не потоков) и порождайте свои N или N + 1 или любые другие процессы.

Более запутанный, крутой и не обязательно лучший способ: если вы можете измерить пропускную способность завершенных единиц работы, вы можете попытаться настроить количество процессов на лету, даже не зная / не обнаруживая количество процессоров / ядер / темы - что-то вроде размера окна TCP, если хотите. Начните с цели из 2 процессов, когда первый завершит измерение производительности, и перейдите к цели + = 1 (т. Е. Доведите общее количество до 3 процессов). Мера, промыть, повторить. Продолжайте увеличивать до тех пор, пока общая пропускная способность продолжает расти, и уменьшайте его, когда снижается. Добавьте немного гистерезиса в смесь и обязательно настройте разумный верхний предел.

Что касается примера с вашим ноутбуком, то да, это многопоточный процессор, несколько потоков принесут пользу некоторым нагрузкам больше, чем другие, а ваш - тот, который от этого не выиграет:)

0 голосов
/ 27 августа 2011

Я думаю, multiprocessing больше подходит для случая, когда работа, которую вы хотите выполнить, выполняется на python, а не совсем другой процесс.Все дело в использовании fork и передаче чего-либо из процесса Python в процесс Python, поэтому я не думаю, что это будет работать для вас.

В вашей текущей реализации, как только будет создано максимальное число подпроцессов, вашкод блокирует порождение новых подпроцессов до тех пор, пока все не завершат текущую серию процессов, потому что Popen.wait() блокирует до этого конкретного подпроцесса .

Я думаю, что вы хотитеos.wait().Я сделал что-то очень похожее , сохранив отображение моих subprocess.Popen экземпляров, отображаемых с помощью pid.Просто увеличьте максимальное количество подпроцессов и позвольте os.wait() сообщить вам, когда завершится один из них.os.wait() даст вам pid всех экземпляров, которые Popen завершит в следующий раз, и вы можете использовать его для выполнения оставшейся очистки для этого подпроцесса .Затем вы позволяете вашему коду раскручивать следующий подпроцесс.

...