使 PHP 中的函数超时


Timeout a function in PHP

有没有办法使函数超时?我有 10 分钟的时间来完成一项工作。该作业包括一个 for 循环,下面是一个示例:

<?php
foreach($arr as $key => $value){
   some_function($key, $value); //This function does SSH and SFTP stuff
}
?>

$arr有 15 个元素,some_function(( 有时可能需要 1 分钟以上。事实上,一旦它被挂起了 5 分钟。

有没有办法让我的函数调用超时并继续处理$arr中的下一个元素?

谢谢!!

这取决于您的实现。 PHP 中 99% 的函数都是阻塞的。这意味着在当前函数完成之前,处理不会继续。但是,如果函数包含循环,则可以添加自己的代码,以便在满足特定条件后中断循环。

像这样:

foreach ($array as $value) {
  perform_task($value);
}
function perform_task($value) {
  $start_time = time();
  while(true) {
    if ((time() - $start_time) > 300) {
      return false; // timeout, function took longer than 300 seconds
    }
    // Other processing
  }
}

另一个无法中断处理的示例:

foreach ($array as $value) {
  perform_task($value);
}
function perform_task($value) {
    // preg_replace is a blocking function
    // There's no way to break out of it after a certain amount of time.
    return preg_replace('/pattern/', 'replace', $value);
}
你想要的是

使用pcntl_alarm函数,它将在超时时触发SIGALRM信号。

例如:

// 10 minutes
pcntl_alarm( 600 );
pcntl_signal(SIGALRM, function() { print( "Timed-out!'n" ); exit( 0 ); });

请参阅此处的PHP手册以获取更多信息:http://php.net/manual/en/function.pcntl-alarm.php

PHP 是单线程的...你必须使用操作系统的能力来分叉另一个进程。

我知道该怎么做的唯一方法是使用 exec 命令分叉另一个完整进程。 将您想要计时的内容放在单独的脚本中,在脚本上致电 exec,然后立即睡眠 10 分钟。 如果在 10 分钟后进程仍在运行,请将其杀死。(你应该通过让命令在后台运行新的 PHP 代码,通过命令行获取它并从 exec 命令返回它来拥有它的 PID(。

您可以尝试使用"curl"来实现这一点。Curl来自PHP - 主要用于做HTTP/FTP的东西,但它支持更多的协议,包括ssh/sftp。我从来没有使用 curl 做过与 ssh/sftp 相关的事情,所以我不能给出任何额外的建议,但你应该能够在这里找到关于 stackoverflow 或其他地方的其他信息。

有一个

选项"CURLOPT_TIMEOUT"可用于配置请求的超时(还有一个选项"CURLOPT_CONNECTTIMEOUT"(。您甚至可以以毫秒分辨率 (CURLOPT_TIMEOUT_MS/CURLOPT_CONNECTTIMEOUT_MS( 指定超时。

无论如何:对于 cronjob,我建议使用脚本在启动时写入的额外"锁定文件",并在完成运行时删除。您可以在脚本中检查此锁定文件,因此如果 cron 在最后一次运行完成之前触发了脚本,您可以退出脚本而无需执行任何进一步操作。这样可以确保您的脚本不会并行执行多次。

您也可以在 PHP 文档中找到有关 CURL 选项和 CURL 本身的更多信息:

  • http://www.php.net/manual/en/function.curl-setopt.php
  • http://www.php.net/manual/en/book.curl.php

不过,您必须确保已安装的 libcurl 和/或 curl for php 支持 SSH/SFTP:

  • 来自 PHP 的 SFTP - 未定义的常量CURLOPT_PROTOCOLS和CURLPROTO_SFTP?
  • SFTP 从 PHP 内部

等。

希望有帮助...

在开始循环之前,设置一个记住time()的变量。在每次迭代结束时,检查当前time()是否大于 60 秒。如果是这样,break.例如:

<?php
$startTime=time();
foreach($arr as $key => $value){
    some_function($key, $value); //This function does SSH and SFTP stuff
    if (time()-$startTime>60) break; //change 60 to the max time, in seconds.
}
?>

看看set_time_limit。现在函数本身并不是你想要的,因为它只考虑执行时间,这意味着现实生活中的 5 秒可能仍然只有 0.2 秒的执行。但是查看链接的原因是为了评论。用户发布了几个解决方案。

对于那些使用命令行的人,请参阅睡眠是如何中断的:

echo date("H:i:s'n");
pcntl_signal(SIGALRM ,function($signal){
echo "arghhh! i got interrupted 'n";
},true);
pcntl_alarm(3);
sleep(20);
pcntl_signal_dispatch();

echo date("H:i:s'n");
pcntl_alarm(3);
sleep(20);
echo date("H:i:s'n");
pcntl_signal_dispatch();
echo "end'n";