Как использовать 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?

Author: Levi Morrison, 2012-11-02

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);
    }
}
 11
Author: Levi Morrison, 2012-11-07 20:12:41