如何解决不影响PHP-CLI的set_time_limit?
#!/usr/bin/php -q
<?php
set_time_limit(2);
sleep(5); // actually, exec() call that takes > 2 seconds
echo "it didn't work again";
答案 0 :(得分:17)
max_execution_time
限制,即set_time_limit
设置的限制,计算(至少在Linux上) PHP进程在工作时花费的时间。< / p>
引用set_time_limit()
的手册页:
注意:
set_time_limit()
功能和配置 仅限指令max_execution_time
影响的执行时间 脚本本身。
任何时间花在 在外面发生的活动 执行脚本,如系统 使用system()
来调用流 操作,数据库查询等 确定时不包括在内 脚本的最长时间 运行。
这不是真的 测量时间为的Windows 实。
当您使用sleep()
时,您的PHP脚本无法正常工作:它只是在等待......所以您等待的5秒钟不会被max_execution_time
限制考虑在内。< / p>
答案 1 :(得分:9)
此处的解决方案是使用pcntl_fork()
。我担心它只是POSIX。 PHP需要使用--enable-pcntl
而不是--disable-posix
进行编译。您的代码应如下所示:
<?php
function done($signo)
{
// You can do any on-success clean-up here.
die('Success!');
}
$pid = pcntl_fork();
if (-1 == $pid) {
die('Failed! Unable to fork.');
} elseif ($pid > 0) {
pcntl_signal(SIGALRM, 'done');
sleep($timeout);
posix_kill($pid, SIGKILL);
// You can do any on-failure clean-up here.
die('Failed! Process timed out and was killed.');
} else {
// You can perform whatever time-limited operation you want here.
exec($cmd);
posix_kill(posix_getppid(), SIGALRM);
}
?>
基本上它的作用是派一个运行else { ... }
块的新进程。在(成功)结束时,我们将警报发送回正在运行elseif ($pid > 0) { ... }
块的父进程。该块具有警报信号(done()
回调)的注册信号处理程序,该处理程序成功终止。在收到之前,父进程会休眠。当超时sleep()
完成后,它会向(可能是挂起的)子进程发送SIGKILL
。
答案 2 :(得分:5)
你能尝试通过exec运行你的php并使用“timeout”命令吗? (http://packages.ubuntu.com/lucid/timeout)
用法:超时[-signal]时间命令。
答案 3 :(得分:4)
非常hackish,但由于我经常使用cli脚本,我承认可耻地过去打了一个类似的hack。需要2个脚本。
您的第一个cron脚本(挂起的脚本)将其starttime和processid记录在一个平面文件中 - &gt;函数getmypid将是你的朋友。每隔(x)分钟从cron运行的第二个脚本检查flatfile,杀死已经通过指定执行时间的任何内容,清除flatfile,甚至可以根据需要登录另一个文件。
祝你好运;)<强>更新强>
记住了这个问题并回来发布了这个问题。在通过Sebastian Bergmann的github帐户搜索时,我偶然发现php-invoker。用作者的话来说:
用于在超时时调用PHP callables的实用程序类。
虽然目前的答案非常适合基于Linux的非便携式使用,但如果需要跨平台解决方案,这个解决方案应该是Windows兼容的,适用于在windoze上运行的那些可怜的灵魂。 Bergmann先生是一名PHP神,我完全保证了剧本的质量。
答案 4 :(得分:4)
我觉得脚本在一个循环中挂起。为什么不简单地执行脚本开始$STARTUP_TIME=time()
,然后在脚本需要退出时继续检查循环?
答案 5 :(得分:2)
我在PHP手册中注意到了这条评论:
请注意,在Linux下, 睡眠时间被忽略,但在 Windows,它算作执行时间。
据我所知,sleep是作为系统调用实现的,因此被PHP as described in the manual忽略。
运行exec()代替 睡觉()那里。和一些exec()的东西 无限期挂起。我也是 寻找从内部杀死它 exec(在linux shell上),就像 exec(kill_after15secs myscript.sh), 但我似乎无法找到那个
我现在看到了实际的问题。假设您在Lunix / Unix环境中工作,您可以围绕这些方面设计解决方案:
<?php $pid = system( 'sh test.sh >test-out.txt 2>&1 & echo $!' ); ?>
猜猜是什么,这捕获了您开始的流程的进程ID。您可以将其与时间戳一起记录到数据库或文本文件中。在另一个运行的cron脚本中,例如,每5分钟运行一次,检索5分钟前创建的所有进程ID并检查它们是否仍在运行:
<?php $status = system( 'ps ' . $pid ); ?>
如果进程仍在运行,则会得到两行输出:
PID TTY STAT TIME COMMAND
2044 ? S 0:29 sh test.sh
如果是这样,请按以下方式终止:
<?php system( 'kill ' . $pid ); ?>
我写了一篇关于creating background processes in PHP的文章(然后追捕他们)。所有的例子都是从那里复制过来的。
所有点连接在一起:
<?php
$pid = system( 'sh test.sh >test-out.txt 2>&1 & echo $!' );
$timer = 300;
while( --$timer ) {
sleep(1);
$status = system( 'ps ' . $pid );
$status = explode( "\n", $status, 2 ); // I am not sure, please experiment a bit here
if ( count( $status ) == 1 || trim( $status[ 1 ] ) == '' ) {
die( 'spawned process ended successfully' );
}
}
system( 'kill ' . $pid );
die( 'spawned process was terminated' );
?>