在PHP中启动新进程/线程的最简单方法

时间:2011-12-17 22:36:56

标签: php multithreading performance process

场景:

  1. 共享托管,因此无法安装新扩展程序+无CRON
  2. 提交的请求需要执行一些繁重的过程。
  3. 我希望客户的答案尽可能快,并且繁重的工作要立即继续,但不能阻止客户端。
  4. 可以在新线程上(如果可能的话)也可以在启动新进程时没有问题。
  5. 这样做的最佳方式是什么?

5 个答案:

答案 0 :(得分:11)

On * nix:

exec('/path/to/executable > /dev/null 2>&1 &');

在Windows上:

$WshShell = new COM('WScript.Shell'); 
$oExec = $WshShell->Run('C:\path\to\executable.exe', 0, false);

这两个都会产生一个新进程,它将同步运行,与父进程完全断开连接。只要您的主持人允许您这样做。

答案 1 :(得分:2)

你可以按键google:关闭连接后继续处理php。

以下与您的问题相关的链接是:

您可以使用belongs命令继续执行而无需用户中止

ignore_user_abort(true);
set_time_limit(0);

使用fastcgi_finish_request提醒客户端停止响应输出。并且您的脚本将继续执行。

一个例子:

// redirecting...
ignore_user_abort(true);
set_time_limit(0);
header("Location: ".$redirectUrl, true);
header("Connection: close", true);
header("Content-Length: 0", true);
ob_end_flush();
flush();
fastcgi_finish_request(); // important when using php-fpm!

sleep (5); // User won't feel this sleep because he'll already be away

// do some work after user has been redirected

答案 2 :(得分:2)

补充@DaveRandom的答案:实际上,您不需要STDERR重定向到STDOUT(使用2>&1)。

但是,如果要防止父进程挂起等待子进程完成,则需要重定向STDOUT。这是必需的,因为exec将返回子进程输出的最后一行,因此,它需要等待子进程STDOUT关闭。

这并不意味着您需要将其重定向到/dev/null。您可以将其重定向到其他文件,甚至重定向到其他文件描述符(例如STDERR1>&2)。

  • exec('/path/to/executable'):将启动一个新进程并等待其完成(即阻止父进程)。
  • exec('/path/to/executable &'):与上述基本相同。
  • $pid = exec('/path/to/executable > /dev/null & echo $!'):将在后台启动一个进程,子进程和父进程并行运行。 /path/to/executable的输出将被丢弃,$pid将接收子进程的PID。

实际上没有必要使用2>&1,因为exec会忽略子进程的STDERR。这也可能是不希望有的原因,因为它将使查找某些错误变得更加困难,因为它们只会被静默丢弃。如果省略2>&1,则可以将父进程的STDERR用管道传输到某个日志文件,稍后在出现问题时可以进行检查:

php /path/to/script.php 2>> /var/log/script_error.log

通过使用上面的代码来启动触发子进程的脚本,将script.php 任何子进程写入STDERR的所有内容都写入日志文件。

答案 3 :(得分:1)

PHP中没有线程。您可以通过发回一个触发Ajax调用的HTML页面来作弊,以便在新请求中启动繁重的进程。但如果它是共享主机,我的猜测是你很快就会达到托管服务提供商对内存,时间或CPU使用量的限制。

答案 4 :(得分:0)

$WshShell = new COM('WScript.Shell');
$oExec    = $WshShell->Run('C:\xampp\php\php.exe C:\xampp\htdocs\test.php -a asdf', 0, true);

无法将argv传递给test.php。

var_dump($argv);