Я использую map_async по назначению - для отображения итератора над несколькими процессорными ядрами с помощью:python map_async, откуда возникают накладные расходы?
cores = mp.cpu_count()
pool = mp.Pool()
r = pool.map_async(func, offsets,callback=mycallback)
r.wait()
func
возвращает Dict, поэтому обратный вызов «сливает» в dicts с помощью:
ddict = defaultdict(set)
def mycallback(w):
for l in w:
for key, value in l.items():
for v in value:
ddict[key].add(v)
взаимозачетов повторяемый, который я тестировал с 1000 - 50 000 элементов.
Если я удаляю r.wait()
, невозможно вернуть весь вывод из звонка map_async
.
Использование r.wait()
, я вижу времена обработки, которые уступают последовательной реализации и не масштабируются, т. Е. Параллельная реализация возрастает во времени экспоненциально, в то время как последовательная версия линейно возрастает.
Я знаю, что func
достаточно дорог, как в серийном, так и параллельно он привязывает мои обрабатывающие ядра.
Где я ввел накладные расходы, используя map_async? Он не находится в функции обратного вызова, так как удаление и замена с помощью result.append
не влияет на время.
РЕДАКТИР Комментариев:
Я двигаюсь большая dicts вокруг, где-то от 1000 - 100000 элементов. Значение - это наборы, которые обычно составляют 3-5 элементов. Таким образом, травление определенно может быть проблемой. Какие альтернативные структуры данных можно было бы предложить, не переходя к чему-то в общей памяти?
apply_async
с аналогичным обратным вызовом, сохранить строкуfor l in w
, возвращает примерно одинаковые результаты. Скорость немного лучше, чем map_async для некоторых наборов задач и немного хуже для других. Значительно хуже используется управляемый dict и присоединяемая очередь.Некоторые испытания времени. Это использует 2 ядра. Поскольку я добавляю дополнительные ядра, я вижу экспоненциальное увеличение, поэтому могу только предположить, что это увеличение вызвано процессом нереста или травления для возврата данных.
принимает точку данных и ищет соседние страны. Это идентичная функция для всех случаев, за исключением необходимости прохождения смещений, указывающих параллельный код, который указывает данные для поиска. Это, по сути, функция поиска KDTree.
Распределенные
Гомогенно1000 точек данных: Последовательный 0.098659992218 | apply_async
0.120759010315 | map_async
0.080078125
10 000 точек данных < ====== ТОЛЬКО УЛУЧШЕНИЕ ПАРАЛЛЕЛЬНЫМИ | Последовательный 0.507845163345 | apply_async
0.446543931961 | map_async
0,477811098099
Случайным Распределенные
10000 точек данных: Последовательный 0.584854841232 | apply_async
1.03224301338 | map_async
0.948460817337
50 000 точек данных: серийный номер 3.66075992584 | apply_async
4.95467185974 | map_async
Некоторый пример времени тестирования/результатов при различных размерах пула был бы полезен и интересен, как и деятельность, выполняемая в вашей отображаемой функции. – mdscruggs
Являются ли ваше возвращение dicts очень большим или содержат данные? Для многопроцессорности необходимо рассортировать результаты, чтобы передавать их назад и вперед, что может быть медленным для больших объемов данных. Тем не менее это не объясняет экспоненциального увеличения времени. Что произойдет, если вы вместо этого перейдете через «смещения» и вызовите 'apply_async' с соответствующим обратным вызовом (т. Е.' Mycallback' с удалением 'for l in w'), а затем' wait' для каждого из этих результатов? В стороне, если вы вызываете 'pool.map_async (..., callback = mycallback) .wait()', вы также можете просто вызвать 'mycallback (pool.map (...))'. – Dougal
@Dougal Отредактировано для комментариев. – Jzl5325