Параллельное выполнение функций в 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