【问题标题】:Timeout a function in PHPPHP中的函数超时
【发布时间】:2012-05-22 04:09:15
【问题描述】:

有没有办法让函数超时?我有 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 中的下一个元素?

谢谢!!

【问题讨论】:

  • 一些问题:是什么,将您限制在 10 分钟? ssh/sftp 作业是否被执行没关系吗?你能通过使用某种队列来解决这个限制吗?
  • 这是一个 crontab 脚本,每 10 分钟运行一次。它正在检查服务器状态并更新数据库。如果我在 1 分钟内没有得到回复,我正在将该服务器设置为慢速服务器...

标签: php function foreach timeout


【解决方案1】:

这取决于您的实施。 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);
}

【讨论】:

  • 谢谢 Mike,但我是 some_function 或 perform_task 是核心功能,我试图避免修改核心方法。
  • 走这条路:创建一个新脚本example.php并在some_function中调用该脚本并定义set_time_limit ... some_function的逻辑将在example.php中执行..
  • 同样的问题,同样的技术。
【解决方案2】:

你想要的是使用 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

【讨论】:

  • 它似乎只适用于sleep() 函数。 curl_exec()file_get_contents() 可悲的是,这个解决方案不会超时。
【解决方案3】:

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

我知道如何做到这一点的唯一方法是使用 exec 命令来分叉另一个完整的进程。把你想要计时的东西放在一个单独的脚本中,在脚本上调用 exec,然后立即休眠 10 分钟。如果在 10 分钟时进程仍在运行,请将其杀死。 (你应该通过让命令在后台运行新的 php 代码,通过命令行获取它并从 exec 命令返回它来获得它的 PID)。

【讨论】:

    【解决方案4】:

    您可以尝试使用“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 本身的更多信息:

    你必须确保你安装的 libcurl 和/或 curl 支持 SSH/SFTP,但是:

    等等

    希望对您有所帮助...

    【讨论】:

      【解决方案5】:

      在开始循环之前,设置一个记住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.
      }
      ?>
      

      【讨论】:

      • 感谢大卫的回答。我不需要打破 for 循环,如果需要超过一分钟,我需要打破 some_function。
      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        对于那些在命令行中的人,看看睡眠是如何被中断的:

        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";
        

        【讨论】:

          猜你喜欢
          • 2016-04-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-09
          相关资源
          最近更新 更多