Как использовать PCNTL для параллельного вызова функции php
У меня есть около 10 различных запросов для разных серверов, и я использовал их для последовательного получения ответа в соответствии с вызовом функции на моем веб-сайте.
Теперь я хочу вызвать свою функцию параллельно для другого запроса сервера. Как только я получу первый ответ от любого из серверов, то захочу остановить остальные процессы.
В настоящее время я вызываю свою функцию следующим образом:
my_launch(1);
my_launch(2);
my_launch(3);
my_launch(4);
my_launch(5);
my_launch(6);
my_launch(7);
my_launch(8);
my_launch(9);
my_launch(10);
Это выполняется последовательно; как я могу запустить этот код параллельно, используя PCNTL?
1 answers
О доступности PCNTL
В PHP встроены некоторые функции PCNTL, но по умолчанию они не включены.
Из php.net инструкции по установке pcntl:
Вам необходимо скомпилировать версию PHP CGI или CLI с параметром конфигурации --enable-pcntl при компиляции PHP, чтобы включить поддержку управления процессами.
Что касается распараллеливания
Если вы знаете количество ядер на вашей машине, то я предложил бы разделить работу на такое количество отделов. Управление процессами работает только в системах, подобных *nix, поэтому у вас, вероятно, есть доступная команда nproc
:
$numberOfProcessors = `nproc`;
Вы разветвляете , чтобы запустить нужное количество процессов, разделяете работу между ними и отправляетесь. Разделение работы может быть трудным, но я уверен, что вы это поймете.
Дамп кода
Я был великодушен, поэтому я пошел дальше и закодировал большую часть этого для вас. Обязательно поймите это, потому что это еще не совсем закончено.
Примечания:
- Получает количество доступных процессоров, вызывая
nproc
, поэтому, если у вас нет этой утилиты, вы должны заменить ее количеством процессов, которые вы хотите выполнить. - Если у вас доступно больше процессоров, чем запрошенных итераций, он не сломается. Он просто использует меньше процессоров.
- Если количество процессов не делится равномерно на количество итераций, родительский процесс будет возьмите оставшиеся итерации.
- Не останавливается после получения первого результата. Для этого вам потребуется один процесс на итерацию. Основной процесс должен вызвать pcntl_wait, когда первый завершится и убьет остальных.
Код:
$procs = `nproc`;
$iterations = 10;
$pids = array();
$iproc = -1;
if ($procs > $iterations) {
$procs = $iterations;
}
function my_launch($i, $proc) {
echo "Process $proc ran iteration $i.\n";
}
$pid = 0;
for ($i = 0; $i < $procs; $i++) {
$pid = pcntl_fork();
if ($pid > 0) {
// I am the parent process
$pids[$pid] = $pid;
} elseif ($pid == -1) {
//error occurred, use available processes only
$nproc = $i;
break;
} else {
//I am the child process.
$iproc = $i;
break;
}
}
$nproc = !empty($nproc) ? $nproc : $procs;
if ($nproc == 0) {
echo "NOTICE: Process could not be forked; proceeding in serial.\n";
for ($i = 0; $i < $iterations; $i++) {
my_launch($i, $iproc);
}
exit;
}
if ($nproc != $procs) {
echo "NOTICE: Only using $nproc processes out of the hoped $procs.\n";
}
$iterationsPerProcess = (int) ($iterations / $nproc);
// children do the main work.
if ($pid == 0) {
$stopAt = $iterationsPerProcess * ($iproc + 1);
for ($i = ($iproc * $iterationsPerProcess); $i < $stopAt; $i++) {
my_launch($i, $iproc);
}
}
if ($pid > 0) {
// parent process picks up the remainder of the work
$i = $nproc * $iterationsPerProcess;
for (; $i < $iterations; $i++) {
my_launch($i, "Main");
}
//wait for children to finish
$status = -1;
foreach ($pids as $createdIndex => $pid) {
pcntl_waitpid($pid, $status);
}
}