Форкинг - дорогая операция. Судя по всему, то, что вы действительно хотите, это мульти многопоточность , а не мульти обработка . Разница в том, что потоки имеют гораздо меньший вес, чем процессы, поскольку потоки используют виртуальное адресное пространство, а процессы имеют отдельные виртуальные адресные пространства.
Я не разработчик PHP, но быстрый поиск в Google показывает, что PHP изначально не поддерживает многопоточность, но есть библиотеки для этой работы.
В любом случае, когда вы поймете, как создавать потоки, вы должны выяснить, сколько потоков создавать. Для этого вам нужно знать, в чем заключается узкое место вашего приложения. Является ли узким местом процессор, память или ввод-вывод? Вы указали в своих комментариях, что вы привязаны к сети, а сеть - это тип ввода / вывода.
Если бы вы были привязаны к процессору, вы получите столько параллелизма, сколько у вас процессорных ядер; больше потоков, и вы просто тратите время на переключение контекста. Предполагая, что вы можете выяснить, сколько всего потоков должно появиться, вы должны разделить свою работу на это количество модулей и сделать так, чтобы каждый поток обрабатывал один модуль независимо.
Если бы вы были связаны с памятью, многопоточность не помогла бы.
Поскольку вы привязаны к вводу / выводу, выяснить, сколько потоков для порождения, немного сложнее. Если на обработку всех рабочих элементов требуется примерно одно и то же время с очень малой дисперсией, вы можете оценить, сколько потоков порождать, измерив, сколько времени занимает один рабочий элемент. Однако, поскольку сетевые пакеты, как правило, имеют очень переменную задержку, это вряд ли имеет место.
Одним из вариантов является использование пулов потоков - вы создаете целую кучу потоков, а затем для каждого элемента для обработки вы видите, есть ли в пуле свободные потоки. Если есть, этот поток выполняет эту работу, и вы переходите к следующему элементу. В противном случае вы ждете, когда поток станет доступным. Выбор размера пула потоков важен - слишком велик, и вы тратите время на ненужные переключения контекста. Слишком мало, и вы слишком часто ждете потоков.
Еще один вариант - отказаться от многопоточности / многопроцессорности и просто выполнить вместо этого асинхронный ввод-вывод. Поскольку вы упомянули, что работаете над одноядерным процессором, это, вероятно, самый быстрый вариант. Вы можете использовать такие функции, как socket_select()
, чтобы проверить наличие данных в сокете. Если это так, вы можете прочитать данные, в противном случае вы переходите на другой сокет. Это требует гораздо большего учета, но вы избегаете ожидания поступления данных в один сокет, когда данные доступны в другом сокете.
Если вы хотите отказаться от потоков и асинхронного ввода-вывода и придерживаться многопроцессорной обработки, все равно может оказаться целесообразным, если обработка каждого элемента будет достаточно дорогой. Затем вы можете выполнить разделение работы следующим образом:
$my_process_index = 0;
$pids = array();
// Fork off $max_procs processes
for($i = 0; $i < $max_procs - 1; $i++)
{
$pid = pcntl_fork();
if($pid == -1)
{
die("couldn't fork()");
}
elseif($pid > 0)
{
// parent
$my_process_index++;
$pids[] = $pid
}
else
{
// child
break;
}
}
// $my_process_index is now an integer in the range [0, $max_procs), unique among all the processes
// Each process will now process 1/$max_procs of the items
for($i = $my_process_index; $i < length($items); $i += $max_procs)
{
do_stuff_with($items[$i]);
}
if($my_process_index != 0)
{
exit(0);
}