Параллельное выполнение функций в PHP

может ли PHP вызвать функцию и не ждать ее возвращения? Что-то вроде этого:

function callback($pause, $arg) {
    sleep($pause);
    echo $arg, "n";
}

header('Content-Type: text/plain');
fast_call_user_func_array('callback', array(3, 'three'));
fast_call_user_func_array('callback', array(2, 'two'));
fast_call_user_func_array('callback', array(1, 'one'));

выводит

one (after 1 second)
two (after 2 seconds)
three (after 3 seconds)

, а не

three (after 3 seconds)
two (after 3 + 2 = 5 seconds)
one (after 3 + 2 + 1 = 6 seconds)

основной скрипт предназначен для запуска как постоянный процесс (TCP-сервер). callback() функция будет получать данные от клиента, выполнять внешний PHP-скрипт, а затем делать что-то на основе других аргументов, которые передаются в callback(). Проблема в том, что основной скрипт не должен ждать внешнего PHP-скрипта заканчивать. Результат внешнего скрипта важен, поэтому exec('php -f file.php &') - это не вариант.


изменить: Многие рекомендовали взглянуть на PCNTL, поэтому кажется, что такой функциональности можно достичь. PCNTL недоступен в Windows, и у меня нет доступа к машине Linux прямо сейчас, поэтому я не могу ее протестировать, но если так много людей посоветовали это, то он должен сделать трюк:)

спасибо всем!

7 ответов


на платформах Unix вы можете включить функции PCNTL и использовать pcntl_fork для развилки процесса и запуска заданий в дочерних процессах.

что-то типа:

function fast_call_user_func_array($func, $args) {
  if (pcntl_fork() == 0) {
    call_user_func_array($func, $args);
  }
}

как только вы позвоните pcntl_fork, два процесса будут выполнять ваш код из одной и той же позиции. Родительский процесс получит PID, возвращенный из pcntl_fork, в то время как дочерний процесс получит 0. (Если есть ошибка, родительский процесс вернет -1, который стоит проверить в рабочий код.)


вы можете проверить управление процессом PHP:

http://us.php.net/manual/en/intro.pcntl.php

Примечание:не продевая, но обработка отдельных процессов. Там больше накладных расходов.


разве это не решит вашу проблему с вилкой, сохраняя родительский процесс свободным для других соединений и действий? См.http://www.php.net/pcntl_fork. Если вам нужен ответ, вы можете прослушать сокет в родителе и написать с ребенком. Простой цикл while(true) с чтением может быть выполнен, и, вероятно, у вас уже есть эта базовая функциональность, Если вы запускаете постоянный TCP-сервер. Другой вариант - отслеживать Ваши идентификаторы childprocess-ids, хранить доступный магазин где-то (файл/база данных/memcached и т. д.), С pcnt_wait в основном процессе с WNOHANG, чтобы проверить, какой процесс вышел, и получить данные из магазина.


вы можете сделать некоторые потоки в PHP, если вы используете метод pcntl_fork.

http://ca.php.net/manual/en/function.pcntl-fork.php

Я никогда не использовал это сам, но это хороший пример того, как использовать его на php.net.


PHP не имеет этой функции, насколько я знаю

вы можете эмулировать функцию, используя другую технику, например, эту: параллельные функции в PHP


PHP не поддерживает многопоточность, поэтому нет другого варианта, кроме использования преимуществ ОС или возможностей обработки нескольких веб-серверов. Обратите внимание, что на самом деле вы можете получить как результат, так и вывод exec:

string exec ( строка $command [, array & $output [, int & $return_var ]] )


вы можете, по крайней мере, предотвратить зависание родительского процесса до тех пор, пока дочерний процесс не будет выполнен, игнорируя дочерние сигналы с помощью pcntl_signal(SIGCHLD, SIG_IGN).

Итак, предположим, вы хотите развить процесс и выполнить другую функцию PHP, которая занимает некоторое время, не заставляя родителя ждать ее завершения (так как вы хотите, чтобы основной процесс закончился своевременно):

pcntl_signal(SIGCHLD, SIG_IGN);
$pid = pcntl_fork();
if ($pid < 0) {
  exit(0);
} elseif (!$pid) {
  my_slow_function();
  exit(0);
}
// Parent keeps executing and finishes before the child does

Если вы хотите выполнить медленный внешний скрипт в качестве дочернего процесса, pcntl_exec handy:

$script = array('/path/to/my/script'); // E.g. /home/my_user/my_script.php
pcntl_exec('/path/to/program/executable',$script); // E.g. /usr/bin/php