PHP max_execution_time 不会超时

5
这并不是关于睡眠是否计入超时等常规问题。好的,这里是问题:我已将PHP的max_execution_time设置为15秒,并且理想情况下,当超过设定限制时应该超时,但实际上没有超时。在更改php.ini文件后,Apache已重新启动,并且ini_get('max_execution_time')也一切正常。有时脚本运行时间长达200秒,这太疯狂了。我根本没有任何数据库通信。脚本所做的所有操作都是在Unix文件系统中查找文件,并在某些情况下重定向到另一个JSP页面。脚本中没有sleep()。
我像这样计算PHP脚本的总执行时间:
在脚本开始时,我设置:
$_mtime = microtime();  
$_mtime = explode(" ",$_mtime);
$_mtime = $_mtime[1] + $_mtime[0]; 
$_gStartTime = $_mtime;

同时,结束时间($_gEndTime)的计算方式也类似。
总时间是在我注册的一个关机函数中计算的:

register_shutdown_function('shutdown');
.............
function shutdown()
{
   ..............
   ..............
   $_total_time = $_gEndTime - $_gStartTime;
   ..............
   switch (connection_status ())
    {
    case CONNECTION_NORMAL:
      ....
      break;
      ....
    case CONNECTION_TIMEOUT:
      ....
      break;
      ......
    }
} 
注意:由于我的PHP版本不兼容,我无法使用$_SERVER['REQUEST_TIME']。这很糟糕-我知道。

1)那么,我的第一个问题显然是为什么即使设置了超时限制,我的PHP脚本仍在执行?
2)Apache有Timeout指令,为300秒,但PHP二进制文件不读取Apache配置,这不应该是问题。
3)有可能有些东西将PHP发送到睡眠模式吗?
4)我是否以错误的方式计算执行时间?有更好的方法吗?


我现在困惑了。PHP巫师-请帮忙。

编辑: 我刚刚发现流操作并不是原因,通过一些日志可以得知延迟在脚本中是随机的,即使没有执行任何流操作。上下文切换可能只是原因之一。但我仍然没有明确的答案。我查阅了Linux上PHP的真实max_execution_time,但我不确定是否要尝试。还有其他建议吗?


1
你知道吗,你可以使用 microtime(true) 立即获取一个 float - deceze
@lonesomeday:你确定吗? - Joey Ezekiel
@JoeyEzekiel 是的。请查看 set_time_limit 的文档。"流操作"明确包括在内。 - lonesomeday
@deceze 是的,我知道。但这是遗留代码,我现在并不真正关注代码质量。无论如何,还是谢谢。 - Joey Ezekiel
抱歉我要问一下,你为什么需要可靠地创建一个PHP超时? - Toby Allen
显示剩余2条评论
2个回答

7

max_execution_time 仅限制脚本执行时间本身 - 您的脚本的 CPU 时间。如果操作系统上下文切换到另一个进程并在那里花费了一些时间,那么也不会被计算在内。因此,测量现实世界的时间并期望在30秒后超时将不会是任何给定时间的真实情况。当然,它也忽略了任何systemexec或网络时间。


3
确实,甚至等待数据库查询或处理数据流也被排除在考虑范围之外。 - Johan
我没有任何系统、exec调用,也不调用任何外部代码。文件系统操作是否计入max_execution_time限制?比如,一个fopen()函数。 - Joey Ezekiel
1
@JoeyEzekiel 即使 不执行任何未计入 max_execution_time 的操作,操作系统上下文切换仍在发挥作用,而你几乎无法对此做任何事情。嗯,你可以通过 renice 命令调整运行 PHP(在这种情况下是 Apache)的进程优先级,但我不建议这样做。 - poncha
1
@JoeyEzekiel 是的,请阅读 PHP 手册页面上的注释:http://php.net/manual/en/function.set-time-limit.php 流操作也会影响时间限制(fopen/fread 等都是流操作)。 - Johan
1
@JoeyEzekiel 你不能将那些操作包含在 max_execution_time 中。为了克服这个问题(有点),你可以使用 register_tick_function 注册一个回调函数来检查已经过去了多少时间,但这非常低效(因为回调函数会被频繁调用并浪费大量的 CPU 周期),我强烈建议不要这样做。 - poncha
显示剩余2条评论

0
如果您需要在一定时间长度后超时(根据评论),为什么不调用以下函数:
 $startscript = microtime();

 //do some stuff

if (microtime() - $startscript > 1500)
{
  dotimeout();
}


  // do more stuff

if (microtime() - $startscript > 1500)
{
  dotimeout();
}

  // do more stuff

if (microtime() - $startscript > 1500)
{
  dotimeout();
}

你大概明白了。虽然不太美观,但可能会起作用。


这种方法在我知道延迟将会发生的情况下或许可行。但在我的情况下,这些延迟是随机的。例如,如果第一个检查已经通过,那么 microtime() - $startscript 的任何值都小于1500,并且如果延迟恰好发生在调用第二个检查之前,那么就又回到了同样的故事。无论如何,还是谢谢! - Joey Ezekiel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接