有时候没有调用PHP注册的shutdown函数

时间:2012-05-16 02:40:20

标签: php

我想做一个长时间的工作而且我无法修改最大执行时间,所以我采取了一个解决方案:当脚本要关闭时,脚本会向自己发送一个http请求,所以脚本可以继续运行。 这是我的测试脚本t.php

<?php 
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__));

function post_request_async($url, ARRAY $data) {
    // Convert the data array into URL Parameters like a=b&foo=bar etc.
    $data = http_build_query($data);
    // parse the given URL
    $url = parse_url($url);
    $host = $url['host'];
    $path = $url['path'];
    $port = isset($url['port']) ? $url['port'] : "80";
    $fp = fsockopen($host, $port, $errno, $errstr, 5);
    if ($fp){
        $req = "";
        $req.="POST $path HTTP/1.0\r\n";
        $req.="Host: $host\r\n";
        $req.="Content-type: application/x-www-form-urlencoded\r\n";
        $req.="Content-length: ". strlen($data) ."\r\n";
        $req.="Connection: close\r\n\r\n";
        $req.= $data;
        fputs($fp, $req);
        fclose($fp);
    }
}

set_time_limit(10);
register_shutdown_function("shutdown_func");

file_put_contents(ROOT.DS."zz.txt", date("Y-m-d H:i:s")." start -->".PHP_EOL, FILE_APPEND);

function shutdown_func(){
    file_put_contents(ROOT.DS."zz.txt", date("Y-m-d H:i:s")." shutdown_func -->".PHP_EOL, FILE_APPEND);
    post_request_async("http://127.0.0.1/t.php", array());
    exit();
}

for(;;) {
    sleep(2);
}
?>

但结果很奇怪: zz.txt

2012-05-16 10:11:42 start -->
2012-05-16 10:11:54 shutdown_func -->
2012-05-16 10:11:54 start -->
2012-05-16 10:12:04 shutdown_func -->
2012-05-16 10:12:04 start -->
2012-05-16 10:12:14 shutdown_func -->
2012-05-16 10:12:14 start -->
2012-05-16 10:12:26 shutdown_func -->
2012-05-16 10:12:26 start -->
2012-05-16 10:12:38 shutdown_func -->
2012-05-16 10:12:38 start -->
2012-05-16 10:12:48 shutdown_func -->
2012-05-16 10:12:48 start -->
2012-05-16 10:12:58 shutdown_func -->
2012-05-16 10:12:58 start -->
2012-05-16 10:13:08 shutdown_func -->
2012-05-16 10:13:08 start -->
2012-05-16 10:13:18 shutdown_func -->
2012-05-16 10:13:18 start -->
2012-05-16 10:13:28 shutdown_func -->
2012-05-16 10:13:28 start -->
2012-05-16 10:13:40 shutdown_func -->
2012-05-16 10:13:40 start -->
2012-05-16 10:13:50 shutdown_func -->
2012-05-16 10:13:50 start -->
2012-05-16 10:14:02 shutdown_func -->
2012-05-16 10:14:02 start -->
2012-05-16 10:14:14 shutdown_func -->
2012-05-16 10:14:14 start -->
2012-05-16 10:14:26 shutdown_func -->
2012-05-16 10:14:26 start -->
2012-05-16 10:14:36 shutdown_func -->
2012-05-16 10:14:36 start -->
2012-05-16 10:14:48 shutdown_func -->
2012-05-16 10:14:48 start -->
2012-05-16 10:14:58 shutdown_func -->
2012-05-16 10:14:58 start -->
2012-05-16 10:15:08 shutdown_func -->
2012-05-16 10:15:08 start -->
2012-05-16 10:15:18 shutdown_func -->
2012-05-16 10:15:18 start -->

php_errors.log

[16-May-2012 02:11:54 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:12:04 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:12:14 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:12:26 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:12:38 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:12:48 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:12:58 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:13:08 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:13:18 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:13:28 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:13:40 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:13:50 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:14:02 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:14:14 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:14:26 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:14:36 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:14:48 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:14:58 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:15:08 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:15:18 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:15:28 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 41
[16-May-2012 02:15:28 UTC] PHP Fatal error:  Maximum execution time of 10 seconds exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 33

看起来关闭函数被调用大约22次并且突然没有被调用。

我的php版本是5.3.9,服务器是IIS 7.5 真的需要一些帮助! 非常感谢!

-----------------------更新1 ------------------- -------------------------

经过一番挖掘,我在php源代码中找到了一个测试脚本。看起来注册的关机功能可能会超时。

<?php
set_time_limit(1);
register_shutdown_function("plop");

function plop() {
    $ts = time();
    while(true) {
        if ((time()-$ts) > 2) {
            echo "Failed!";
            break;
        }
    }
}
plop();
?>

结果是:

Fatal error: Maximum execution time of 1 second exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 9

Fatal error: Maximum execution time of 1 second exceeded in E:\eclipse_php_workspace\caijiche_new2\t.php on line 9

1 个答案:

答案 0 :(得分:0)

从开始到结束需要12秒(请参阅zz.txt中的计时器),最长执行时间设置为10秒。所以有一个问题。

通常我将时间限制截止设置为(最大执行时间 - 5秒),但由于您只有10秒和2秒覆盖,您应该将关机设置为7秒。


如果从浏览器启动它,可能优先实际从META刷新指令执行“调用自身”。这样,您就可以发布一个包含状态和元刷新的小HTML页面。 (也是我的首选路径!)如果您运行的是cron或其他后端进程而不是浏览器,请忽略。


编辑(以保存输入太多评论)以回应“它现在停止了,但几分钟后又回来了”。

我猜测的是,如果你仍然有PHP脚本调用自己,它可能会烧掉越来越多的内存,永远不会让iteslf进行垃圾收集。 Apache中的每个PHP脚本都需要大约10MB的Apache开销,另外还有2-3MB的PHP脚本 - 所以你自己调用的越多,它就会越多,最终会慢下来。

所以你需要回到其中一个建议:

a)如果从浏览器调用,选择PHP调用自身,则发出

<html>
   <head>
      <meta http-equiv="refresh" content="1; url=http://127.0.0.1/t.php">
   </head>
   <body>
     Echo going to <a href="http://127.0.0.1/t.php">http://127.0.0.1/t.php</a>
   </body>
</html>

这意味着在PHP脚本中调用自身; PHP也可以进行呼吸并且可以进行垃圾收集,尽管只需要一个简单的脚本运行就不需要中断 - 停止循环应该将其排序。

问题:如果您的连接失败,或者互联网失败,那么响应将不会发生并且脚本将中断,因此:

b)这种方法的一个变体是创建一个每10秒调用一次服务器的javascript。超时后不要做任何事情因为Javascript会再次开始这个过程。

c)最好的方法,如果你想让它“永远”运行,请运行PHP脚本作为命令行(php -q /var/www/html/Myphp.php&gt; / dev / nul)一份计划工作。将cron作业设置为每分钟运行一次。向脚本添加一个计数器,每次调用自身时都会递增,然后在第6次调用(即1分钟)后停止。这样,在脚本死亡之前,您最多循环5次并允许自己清理。

d)或者,如果您可以编写快速shell脚本,只需创建调用PHP命令行的shell脚本,然后等待10秒再调用6次。从每分钟运行的cron触发该脚本。这样就不会产生Apache开销(保存套接字,节省内存)以及避免出现问题。

e)还有其他变体 - 取决于您在服务器上获得的权限......

不是很有希望他们会解决你的问题,但是一个无休止地调用自己的函数就是编程禁忌,所以我至少要给第一个编程,看它是否有效,然后研究更复杂的问题。