Использование multiprocessing
требует отправки рабочим процессам информации о выполняемой функции, а не только аргументы для передачи. Эта информация передается травлением , что информация в основном процессе, отправка его в рабочий процесс и ее рассыпание.
Это приводит к основной проблеме:
Травление функции с аргументами по умолчанию дешево; он только замачивает имя функции (плюс информация, чтобы Python знал, что это функция); рабочие процессы просто ищут локальную копию имени. У них уже есть именованная функция f
, чтобы найти ее, поэтому ей почти ничего не стоит.
Но травление функции partial
включает в себя травление основной функции (дешево) и всех аргументы по умолчанию ( дорогие , когда аргумент по умолчанию - 10M list
). Поэтому каждый раз, когда задача отправляется в случае partial
, она травит связанный аргумент, отправляет его в рабочий процесс, рабочий процесс распаковывается, а затем выполняет «настоящую» работу. На моей машине этот рассол имеет размер примерно 50 МБ, что является огромным объемом накладных расходов; в быстрых тестах времени на моей машине, травление и рассыпание 10 миллионов длинной list
из 0
занимает около 620 мс (и это игнорирует накладные расходы на фактическую передачу 50 МБ данных).
partial
должны рассосаться таким образом, потому что они не знают своих имен; при расчете функции, подобной f
, f
(будучи def
-ed) знает свое квалифицированное имя (в интерактивном интерпретаторе или из основного модуля программы это __main__.f
), поэтому удаленная сторона может просто воссоздайте его локально, выполнив эквивалент from __main__ import f
. Но partial
не знает его имени; конечно, вы назначили его g
, но ни pickle
, ни partial
сами не знают, что это доступно с квалифицированным именем __main__.g
; его можно было бы назвать foo.fred
или миллион других вещей. Поэтому он должен pickle
получить информацию, необходимую для воссоздания целиком с нуля. Это также pickle
для каждого вызова (не один раз на одного рабочего), потому что он не знает, что вызываемый не меняет родителя между рабочими элементами, и он всегда пытается обеспечить его отправку в актуальное состояние.
У вас есть другие проблемы (создание временного времени для list
только в случае partial
и незначительные накладные расходы при вызове функции partial
, завершенной или вызывающей функцию напрямую), но это chump изменение относительно накладного травления для каждого вызова и разблокировка partial
добавляется (первоначальное создание list
добавляет одноразовые служебные данные чуть ниже половины того, что каждый цикл pickle / unpickle расходы, накладные расходы для вызова через partial
меньше, чем микросекунда).
Используйте usort и обеспечьте пользовательскую функцию сравнения, которая использует положение ключа в Вашем массиве "упорядочивания" для определения порядка сортировки, например, чего-то как:
function cmp($a, $b)
{
global $author_array;
$pos1=array_search ($a->ID, $author_array);
$pos2=array_search ($b->ID, $author_array);
if ($pos1==$pos2)
return 0;
else
return ($pos1 < $pos2 ? -1 : 1);
}
usort($user_results, "cmp");
Я не уверен, будет ли это значительно медленнее, чем другие примеры, но это кажется более простым. Может случиться так, что Вы могли создать массив $user_results как ассоциативный для начала, с помощью идентификатора в качестве ключа, затем можно легко сделать поиски.
$hash = array();
$result = array();
foreach ($user_results as $obj) {
$hash[$obj->ID] = $obj;
}
foreach ($author_array as $id) {
$result[] = $hash[$id];
}