Я использую multiprocessing.Pool.map для параллельного запуска кода на моей рабочей станции, которая имеет 10 физических ядер (20 ядер, если я также включу логические).
Подводя итог моему коду, мне нужно провести некоторые вычисления с 2080 матрицами. Итак, я делю 2080 матриц на 130 групп, каждая из которых содержит 16 матриц.
Затем расчет этих 16 матриц распределяется по 16 ядрам (следует ли использовать только 10, поскольку у меня только 10 физических ядер?) С использованием multiprocessing.Pool.map.
Мои вопросы:
(1) Когда я отслеживаю использование ЦП в «системном мониторе» в Ubuntu, я часто обнаруживаю, что только 1 загрузка ЦП показывает 100% вместо 16 ЦП, показывающих 100% использования. 16 CPU показывают 100% использование только на короткое время. Почему это происходит? Как это улучшить?
(2) Смогу ли я сократить время вычислений, разделив 2080 матриц на 104 группы по 20 матриц в каждой, а затем распределив вычисление этих 20 матриц по 10 или 16 ядрам?
Мой фрагмент кода выглядит следующим образом:
def f(k):
adj=np.zeros((9045,9045),dtype='bool')
# Calculate the elements of the matrices
return adj
n_CPU=16
n_networks_window=16
window=int(2080/n_networks_window) #Dividing 2080 matrices into 130 segments having 16 matrices each
for i in range(window):
range_window=range(int(i*2080/window),int((i+1)*2080/window))
p=Pool(processes=n_CPU)
adj=p.map(f,range_window)
p.close()
p.join()
for k in range_window:
# Some calculations using adj
np.savetxt(') # saving the output as a txt file
Любая помощь будет действительно полезна, поскольку я впервые распараллеливаю код Python.
Спасибо.
Обновлено: Я попробовал следующие изменения в коде, и теперь он работает нормально: pool.imap_unordered (f, диапазон (2080), chunksize = 260)
Я сделаю это. На всякий случай, если есть другая альтернатива, это сэкономит время!
Какая версия Python? Соответствует ли ваш процесс какому-либо из примеров в документации?
Я использую 2.7.12
Поддержка многопроцессорности Python, вероятно, не очень сильно нарушена, но я всегда обнаруживал, что легче управлять распараллеливанием на уровне оболочек оболочки вокруг моих сценариев Python.
Я не думаю, что есть лучший способ, чем провести эксперимент. Повышение производительности за счет рабочих пулов - непростая задача. Несколько процессов действительно позволяют выйти из GIL и по-настоящему параллельное выполнение, но ваш пул будет использовать очереди для передачи входных и выходных данных между процессами, и это может замедлить работу, если вы передаете много данных. Так что универсального ответа не существует, это зависит от вашего конкретного случая.
Вы искали python multiprocessing not using all cores
? Подходит ли какой-либо из вопросов и ответов вашему варианту использования или объясняет / решает вашу проблему?
@wii: Две вещи, которые я узнал после прочтения других сообщений: (1) Всегда лучше запускать многопроцессорность с N-1 физическими ядрами. (2) Было предложение поместить p.join () вне цикла for ... Я должен это проверить.
Ваша проблема здесь:
for i in range(window):
# [snip]
p=Pool(processes=n_CPU)
adj=p.map(f,range_window)
p.close()
p.join()
# [snip]
Вы создаете новый пул в каждом цикле и отправляете в него только несколько заданий. Чтобы цикл продолжался, нужно завершить несколько заданий, прежде чем можно будет выполнить больше заданий. Другими словами, вы не используете весь потенциал параллелизма.
Что вам нужно сделать, так это создать единый пул, отправить все задания, а затем, вне цикла, присоединиться:
p=Pool(processes=n_CPU)
for i in range(window):
# [snip]
p.map_async(f,range_window)
# [snip]
p.close()
p.join()
Обратите внимание на использование map_async
вместо map
: это опять же, чтобы избежать ожидания завершения небольшой части заданий перед отправкой новых заданий.
Еще лучший подход - вызвать map
/ map_async
только один раз, создав один объект диапазона и избегая цикла for:
with Pool(processes=n_CPU) as p:
p.map(f, range(2080)) # This will block, but it's okay: we are
# submitting all the jobs at once
Что касается вашего вопроса о количестве используемых процессоров, прежде всего обратите внимание, что Pool будет использовать все доступные процессоры (по умолчанию возвращается os.cpu_count()
, если вы не укажете аргумент processes
- попробуйте.
Мне непонятно, что вы имеете в виду под 10 физическими ядрами и 20 логическими. Если вы говорите о гиперпоточности, тогда ничего страшного: используйте их все. Если вместо этого вы говорите, что используете виртуальную машину с большим количеством виртуальных процессоров, чем хост-процессоры, то использование 20 вместо 10 не будет иметь большого значения.
Большое спасибо. Я попробую ваши предложения и дам вам знать через несколько дней.
2)
- просто попробуйте и убедитесь.