2010-11-02 180 views
8

我有运行为执行一组简单的任务是为循环数据库中的每个用户,需时约30分钟即可完成cron作业的PHP脚本。这个过程从每个小时开始,需要尽可能快速和高效。问题我有,就像任何服务器脚本,执行时间不同,我需要找出最好的克朗时间设置。cron作业PHP脚本,需要很长的执行时间

如果我运行cron的每一分钟,我需要20秒分钟结束前停止脚本的最后一个循环,以确保电流回路的时间完成。在一小时内,这会浪费大量时间。

我想知道,如果它是一个坏主意,简单去除PHP执行时间限制并运行该脚本每隔一小时,并让它运行到完成....这是一个坏主意?

+1

您的cron作业调用运行PHP或从命令行使用PHP的网站? 我不完全理解第二段 - 为什么你停止处理并重新启动每一分钟? – 2010-11-02 22:46:07

+0

我想你可能会在这里得到一些更有效的答案,如果你解释工作需要做什么。可能有更有效的方法来做到这一点。 – ocodo 2010-11-02 22:50:59

回答

5

假设您希望尽快完成工作,请不要使用cron。 Cron对于需要在特定时间发生的事情非常有用。它经常被滥用来模拟后台进程,只要工作出现,理想情况下就可以处理工作。你应该写一个连续运行的守护进程。 (注意:你也可以看看一个消息/工作队列类型系统,有很好的库也可以这样做)

你可以使用pcntl functions从头开始编写一个守护进程(因为你不关心多个工作进程,这是super-easy得到一个进程在后台运行),或欺骗,只是让一直运行的脚本,并通过screen运行它,或利用一些固体库代码像PEAR的System:Daemonnanoserv

一旦守护进程的东西是照顾,你真正关心的是有永久运行的循环。您需要注意您的脚本不会泄漏内存或占用太多资源。

一般情况下,你可以这样做:

<?PHP 
// some setup code 
while(true){ 
    $todo = figureOutIfIHaveWorkToDo(); 
    foreach($todo as $something){ 
     //do stuff with $something 
     //remember to clean up resources so you don't leak memory! 
     usleep(/*some integer*/); 
    } 
    usleep(/* some other integer */); 
} 

,它会工作得很好。

0

我在过去使用过类似的长时间运行任务的php命令行界面。您可能不想删除任何请求的执行时间限制。

0

听起来像一个好主意,如果很少有可能需要一个多小时。但是,请注意,错误的错误可能是一个非常好的方式,使其花费比预期更长的时间。

为了避免各种令人讨厌的问题,您应该有一个带有脚本进程ID的警卫文件。在启动时,您应该检查以确保文件不存在,或者如果确实文件中的进程标识不存在(通过kill(pid,0)调用)。如果满足这些条件,请使用脚本的PID创建一个新文件,并在完成后删除文件。

这与许多守护程序用来确保它尚未运行的技巧相同。如果守护进程突然中断,文件将仍然存在,但其中进程的PID不太可能正在运行。

1

将时间限制设置为0,并让它做它的事情是相当典型的基于PHP的cronjobs(以我的经验),但这也是你应该问自己几个重要问题,如“我应该用编译语言重写这份工作?“和“我是否用我的所有工具(数据库等)达到最高效率?”

也就是说,也许比彻底删除时间限制更好的是将其设置为您实际需要的上限。如果这意味着48分钟,然后set_time_limit(48 * 60);

0

根据您的脚本做什么,这可能会导致问题,如果您删除的时间限制。例如,如果您正在轮询作业正在运行时没有响应的外部服务器,并且您的cron需要2小时而不是30分钟才能完成,那么即使以前的那些避难所也可能会产生一堆PHP进程尚未完成。这可能会导致系统不稳定和崩溃。

你可能有两种选择:

  • 确保您的脚本的其它实例正在运行的事前,在启动否则退出()。
  • 考虑将你的cronjob改成一个守护进程。
1

我真的认为你不应该把时间设定为0,那只是寻找麻烦。最多可以将其设置为59 * 60秒,但将其设置为0可能会导致安全问题,如果脚本挂起,它将几乎永远挂起,直到服务器主机停止执行。这样做被认为是不好的做法。

0

是否必须像发条一样每小时运行一次?

如果不拆分作业(你提到它不只是一个简单的任务)每小时执行一次任务?

或者按用户划分,在小时内做A-M,然后在下一个N-Z?

2

而不是设置max_execution_time你也可以使用set_time_limit()来重置每个循环的计数器。这将确保您的脚本永远不会耗尽时间,除非在当前循环中存在严重的挂起(并且花费的时间超过max_execution_time)。

基本上,这应该让您的脚本运行,只要它需要两个set_time_limit()调用之间的30秒超时。

+0

这是一个很好的建议。我不确定你为什么没有足够的选票。 – dinwal 2017-11-09 12:15:21