Executing functions parallelly in PHP

2019-02-06 13:01发布

Can PHP call a function and don't wait for it to return? So something like this:

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'));

would output

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

rather than

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

Main script is intended to be run as a permanent process (TCP server). callback() function would receive data from client, execute external PHP script and then do something based on other arguments that are passed to callback(). The problem is that main script must not wait for external PHP script to finish. Result of external script is important, so exec('php -f file.php &') is not an option.


Edit: Many have recommended to take a look at PCNTL, so it seems that such functionality can be achieved. PCNTL is not available in Windows, and I don't have an access to a Linux machine right now, so I can't test it, but if so many people have advised it, then it should do the trick :)

Thanks, everyone!

7条回答
疯言疯语
2楼-- · 2019-02-06 13:44

You can, at least, prevent the parent process from hanging until the child process is done by ignoring the child signals using pcntl_signal(SIGCHLD, SIG_IGN).

So, let's say you want to fork a process and execute another PHP function that takes a while without making the parent wait for it to finish (since you want the main process to finish in a timely manner):

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

If you want to execute a slow external script as the child process, pcntl_exec is 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
查看更多
劳资没心,怎么记你
3楼-- · 2019-02-06 13:51

Wouldn't it solve your problem to fork, keeping the parent process free for other connections & actions? See http://www.php.net/pcntl_fork. If you need an answer back you could possibly listen to a socket in the parent, and write with the child. A simple while(true) loop with a read could possibly do, and probably you already have that basic functionality if you run a permanent TCP server. Another option would be to keep track of your childprocess-ids, keep a accessable store somewhere (file/database/memcached etc), with a pcnt_wait in the main process with a WNOHANG to check which process has exited, and retrieve the data from the store.

查看更多
\"骚年 ilove
4楼-- · 2019-02-06 13:53

PHP doesn't have this functionality as far as I know

You can emulate the function using a different technique, like this one: Parallel functions in PHP

查看更多
Deceive 欺骗
5楼-- · 2019-02-06 13:55

You can check out PHP Process Control:

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

Note: This is not threading, but the handling of separate processes. There is more overhead attached.

查看更多
甜甜的少女心
6楼-- · 2019-02-06 14:00

PHP does not support multi-threading, so there's no other option than taking advantage of the OS or the web server multi processing capabilities. Note that actually you can fetch both the result and output of exec:

string exec ( string $command [, array &$output [, int &$return_var ]] )

查看更多
淡お忘
7楼-- · 2019-02-06 14:01

On Unix platforms you can enable the PCNTL functions, and use pcntl_fork to fork the process and run your jobs in child processes.

Something like:

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

Once you call pcntl_fork, two processes will execute your code from the same position. The parent process will get a PID returned from pcntl_fork, while the child process will get 0. (If there's an error the parent process will return -1, which is worth checking for in production code).

查看更多
登录 后发表回答