PHP脚本的Cron作业需要非常长的执行时间

时间:2010-11-02 22:40:31

标签: php cron

我有一个php脚本作为cron作业运行,它执行一组简单的任务,为数据库中的每个用户循环,大约需要30分钟才能完成。这个过程每小时开始一次,需要尽可能快速有效。我遇到的问题就像任何服务器脚本一样,执行时间也各不相同,我需要找出最佳的cron时间设置。

如果我每分钟运行一次cron,我需要在分钟结束前20秒停止脚本的最后一个循环,以确保当前循环及时完成。在一小时内,这会浪费很多时间。

我想知道简单地删除php执行时间限制并且每小时运行一次脚本并让它运行完成是一个坏主意....这是一个坏主意吗?

8 个答案:

答案 0 :(得分:7)

假设您希望尽快完成工作,请不要使用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 */); 
}

它会很好用。

答案 1 :(得分:6)

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

基本上这应该让你的脚本在需要时运行,同时在两次set_time_limit()次调用之间给它30秒的超时。

答案 2 :(得分:1)

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

尽管如此,或许比完全删除时间限制更好的是将其设置为您实际想要的上限。如果这意味着48分钟,那么set_time_limit(48 * 60);

答案 3 :(得分:1)

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

如果花费超过一个小时的可能性很小,那就太棒了。但请注意,错误的错误可能是让它花费的时间超过预期的一种非常好的方式。

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

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

答案 6 :(得分:0)

根据脚本的功能,如果删除时间限制,可能会导致问题。如果按照示例,您正在轮询在作业运行时没有响应的外部服务器,并且您的cron需要2小时而不是30分钟才能完成,您可能会获得一堆PHP进程,即使之前的进程尚未启动还没完成。这可能会导致系统不稳定和崩溃。

您可能有两种选择:

  • 确保事先没有其他脚本实例正在运行,否则start()on start。
  • 考虑将您的cronjob更改为守护进程。

答案 7 :(得分:0)

它必须像发条一样每小时运行一次吗?

如果没有拆分工作(你提到它不止一个简单的任务)每小时做一次任务?

或按用户分割,按小时做A-M,然后按下N-Z?