【问题标题】:most simple way to start a new process/thread in PHP在 PHP 中启动新进程/线程的最简单方法
【发布时间】:2012-01-22 19:42:25
【问题描述】:

场景:

  1. 共享主机,因此无法安装新扩展 + 没有 CRON
  2. 提交的请求需要执行一些繁重的过程。
  3. 我希望尽快回复客户,并立即继续繁重的工作,但不要阻止客户。
  4. 可以在一个新线程上(如果可能的话)启动一个新进程也没有问题。

最好的方法是什么?

【问题讨论】:

  • PHP 不能(当前)是多线程的。 非常我经常不高兴。
  • 嗯,有些东西是可以模仿的。

标签: php multithreading performance process


【解决方案1】:

在 *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);

这两者都将产生一个新进程,该进程将异步运行,完全与父进程断开连接。只要你的主人允许你这样做。

【讨论】:

  • 我可以将 /dev/null 更改为我选择的日志文件吗?
  • 我想是的,只要您将 STDOUT STDERR 重定向到不是父进程的某个地方,并以& 为后缀,它应该可以工作。 TBH,我一直只是 /dev/nulled 它,所以你真的只需要吮吸它然后看看......
  • 在共享主机上启动任意外部进程?祝你好运。
  • @JBNizet 我可以像上面一样在我的外部 PHP 脚本启动,它们实际上会运行我认为永远 - 我有一个运行一个多星期作为实验一次。
  • 哇。那你比我幸运多了:-)
【解决方案2】:

你可以通过key google: php 关闭连接后继续处理。

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

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

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

【讨论】:

  • 欢迎来到 SO。您应该检查答案的格式。到目前为止,您似乎将所有内容都放在了代码块中,而您的答案中有一部分不是代码。
【解决方案3】:

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

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

这并不意味着您需要将其重定向到/dev/null。您可以将其重定向到其他文件,甚至重定向到其他文件描述符(例如 STDERR:1>&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的所有内容都将写入日志文件。

【讨论】:

    【解决方案4】:

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

    【讨论】:

    【解决方案5】:
    $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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-12
      • 2023-03-27
      • 2013-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-20
      相关资源
      最近更新 更多