PHP无限循环

7

我需要一个在php中可以自行执行而不需要cron帮助的函数。我已经想出了以下代码,它对我很有效,但由于它是一个无限循环,会给我的服务器或脚本带来问题吗?如果有问题,你能给我一些建议或替代方案吗?谢谢。

$interval=60; //minutes
set_time_limit(0);

while (1){
    $now=time();
    #do the routine job, trigger a php function and what not.
    sleep($interval*60-(time()-$now));
}

你需要一个 PHP 守护进程。 - user557846
个人而言,我不会使用PHP来进行守护进程。因为可能会出现内存泄漏的情况,你需要每个月左右重启一次。我建议使用其他编译语言代替。 - Aziz Saleh
由于您是新手PHP,也许您应该解释一下为什么需要这个,可能有更好的想法。 - user557846
https://dev59.com/m2ox5IYBdhLWcg3wDgIz - Parfait
@Dagon 我正在开发一个网络应用程序,基本上每15分钟循环一次订单,并将其分配给一个空闲的送货员。 - alagu
4个回答

13

我们在实际的系统环境中使用了无限循环来等待短信并进行处理。我们发现这样做会导致服务器资源随着时间的推移变得更加紧张,必须重新启动服务器以释放内存。

我们遇到的另一个问题是,当您在浏览器中执行带有无限循环的脚本时,即使您按下停止按钮,它也会继续运行,除非您重新启动Apache。

    while (1){ //infinite loop
    // write code to insert text to a file
    // The file size will still continue to grow 
    //even when you click 'stop' in your browser.
    }

解决方案是在命令行上将PHP脚本作为守护进程运行。以下是方法:

nohup php myscript.php &

& 将您的进程放到后台。

我们不仅发现这种方法内存占用更少,而且您还可以通过运行以下命令而无需重启 Apache 就可以终止它:

kill processid

编辑:正如 Dagon 指出的那样,这并不是真正运行 PHP 作为“守护程序”的方式,但使用 nohup 命令可以被认为是以“穷人”的方式运行进程作为守护进程。


从命令行调用PHP脚本并不会使其成为守护进程。 - user557846
这种过程是Apache和PHP不擅长的,但像node.js这样的新技术可以胜任。我认为这种任务不应该使用PHP完成,否则它最终会影响到你的项目。 - scrowler
@Dagon,什么才能使它成为守护进程? - zoltar

2
您可以使用 time_sleep_until() 函数。它将返回 TRUE 或 FALSE。
$interval=60; //minutes
  set_time_limit( 0 );
  $sleep = $interval*60-(time());

  while ( 1 ){
     if(time() != $sleep) {
       // the looping will pause on the specific time it was set to sleep
       // it will loop again once it finish sleeping.
       time_sleep_until($sleep); 
     }
     #do the routine job, trigger a php function and what not.
   }

2

有许多方法可以在PHP中创建守护进程,并且这已经存在很长时间了。

仅仅在后台运行某些东西是不够的。例如,如果它尝试打印一些内容并且控制台已关闭,则程序会停止。

我在Linux上使用的一种方法是在php-cli脚本中使用pcntl_fork(),它基本上将您的脚本分成两个PID。让父进程自杀,并让子进程再次分叉。然后让父进程自杀。子进程现在已完全独立,可以愉快地挂在后台做任何您想做的事情。

$i = 0;
do{
    $pid = pcntl_fork();
    if( $pid == -1 ){
        die( "Could not fork, exiting.\n" );
    }else if ( $pid != 0 ){
        // We are the parent
        die( "Level $i forking worked, exiting.\n" );
    }else{
        // We are the child.
        ++$i;
    }
}while( $i < 2 );

// This is the daemon child, do your thing here.

不幸的是,如果该模型崩溃或服务器重新启动,它没有自我重启的方法。(这可以通过创意解决,但是...)
要获得重新启动的鲁棒性,请尝试使用Upstart脚本(如果您使用Ubuntu)。这里有一个教程- 但我还没有尝试过这种方法。

刚刚发现了将PHP脚本作为守护进程运行的问题,该回答比我之前的回答更全面。 - Amgine

1

while(1) 表示无限循环。如果您想要跳出循环,应该使用条件语句 break

while (1){ //infinite loop
    $now=time();
    #do the routine job, trigger a php function and what no.
    sleep($interval*60-(time()-$now));
    if(condition) break; //it will break when condition is true
}

其实我不想让它出问题,我只是想知道后果会是什么。 - alagu

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