set_time_limit不影响PHP-CLI

Dev*_*rim 14 php

如何解决不影响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";
Run Code Online (Sandbox Code Playgroud)

Pas*_*TIN 18

max_execution_time限制,这是什么 set_time_limit规定,计数(至少在Linux上)是由PHP的过程中度过,而工作的时间.

引用手册的页面set_time_limit():

注:set_time_limit()功能和配置指令max_execution_time 只影响脚本本身的执行时间.在确定脚本运行的最长时间时,不包括在
执行脚本之外发生的任何活动,例如系统调用system(),流操作,数据库查询等.
在测量时间真实的Windows上,情况并非如此.

当您正在使用时sleep(),您的PHP脚本无法正常工作:它只是在等待......所以您等待的5秒不会被max_execution_time限制考虑在内.


mje*_*jec 10

这里的解决方案是使用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);
}

?>
Run Code Online (Sandbox Code Playgroud)

基本上它的作用是fork一个运行else { ... }块的新进程.在(成功)结束时,我们将警报发送回正在运行elseif ($pid > 0) { ... }块的父进程.该块具有用于警报信号(done()回调)的注册信号处理程序,该信号处理程序成功终止.在收到之前,父进程会休眠.超时sleep()完成后,它会向SIGKILL(可能是挂起的)子进程发送一个.


Ste*_*lin 5

非常 hackish,但由于我经常使用 cli 脚本,所以我羞愧地承认过去曾进行过类似的 hack。需要 2 个脚本。

您的第一个 cron 脚本(挂起的脚本)将其启动时间和 processid 记录在一个平面文件中 -> 函数 getmypid 将成为您的朋友。每 (x) 分钟从 cron 运行的第二个脚本会检查平面文件,杀死所有已超过指定执行时间的文件,清除平面文件,甚至根据需要登录另一个文件。

祝你好运 ;)

更新:

想起了这个问题,又回来发帖了。在翻阅 Sebastian Bergmann 的 github 帐户时,我偶然发现了php-invoker。用作者的话来说:

用于调用具有超时功能的 PHP 可调用对象的实用程序类。

虽然当前的答案对于基于 Linux 的非便携式使用非常好,但如果需要跨平台解决方案,则对于那些在 windows 上运行的可怜的灵魂来说,该解决方案应该与 Windows 兼容。Bergmann 先生作为 PHP 大神,我完全保证脚本的质量。


Eam*_*orr 5

你能尝试通过exec运行你的php并使用"超时"命令吗?(http://packages.ubuntu.com/lucid/timeout)

用法:超时[-signal] time命令.