【问题标题】:How can I run my program code after fixed intervals?如何在固定间隔后运行我的程序代码?
【发布时间】:2011-04-11 08:35:27
【问题描述】:

我有 this Perl script 用于监视 Linux 中的文件夹。

为了不断检查目录的任何更新,我有一个 while 循环,在连续循环之间休眠 5 分钟:

while(1) {

    ...
    sleep 300;
}

my other question 上没有人建议使用 cron 进行调度而不是 for 循环。

与使用 crontab 提交 cronjob 相比,这个 while 构造在我看来很难看:

0 */5 * * * ./myscript > /dev/null 2>&1
  • cron 是正确的选择吗?使用 while 循环结构有什么好处吗?
  • 除了循环和 cron 之外,还有其他更好的方法吗?

另外,我使用的是 2.6.9 内核版本。

【问题讨论】:

  • 如果循环在 301, 302, 303, ... 秒而不是 300 秒时略微漂移,会出现什么问题?由于在“构建”到达和被发现之间已经存在不确定(但有界 - 到 300 秒)的延迟,所以再过一两秒会产生任何实际影响吗?
  • @Jonathan:不,这没有任何区别。 300 秒只是为了避免过于频繁地检查并避免为单个更新发送 10 封邮件(如果循环正在运行并且添加了 10 个文件,它可能会准确检查每个添加的时间并分别为每个更新发送邮件,这不是我想要的)。

标签: perl unix cron


【解决方案1】:

我使用while 解决方案的唯一原因是,如果我需要我的代码每分钟运行一次以上,或者它需要立即响应外部事件,这两种情况似乎都不是在这里。

我的想法通常是这样的:cron 几十年来已经过数以百万计的人的测试,因此它至少与我刚刚串在一起的代码一样可靠。

即使在我使用过while 的情况下,我仍然有一个cron 作业来重新启动我的脚本以防万一失败。

我的建议是简单地使用cron。这就是它的设计目的。而且,顺便说一句,我很少将输出重定向到/dev/null,这使得调试变得太难了。通常我只是重定向到/tmp 文件系统中的一个文件,这样我就可以看到发生了什么。

只要你有一个自动清理程序,你就可以追加,如果你担心有人看到输出中的东西,你甚至可以写到一个更私密的位置。

不过,最重要的是,如果您丢弃输出,则无法分析罕见的故障。如果你认为你的工作没有错误,那么无论如何,把输出扔掉,但我很少认为我的脚本没有错误,以防万一。

【讨论】:

  • +1 表示“不要丢弃程序尝试报告的错误”部分。
  • 您可以通过在脚本运行之前引入延迟来让 cron 以超过每秒一次的速度运行作业。例如,要让foo.sh 每秒运行四次,您可以说:* * * * * foo.sh* * * * * sleep .25; foo.sh* * * * * sleep .5; foo.sh* * * * * sleep .75; foo.sh
  • @Chas。 Owens - cron 的分辨率是每分钟一次,而不是每秒。但当然,您的睡眠解决方案仍然适用。
  • 您还可以将作业的输出转储到 logger(1),它会将其转储到您配置的任何 syslog 文件中,并且这些日志将由系统使用的任何日志轮转器维护。试试yourscriptname | logger -t yourscriptname
  • while() 方法在处理长时间运行并且您不想冒同时调用脚本导致混乱的风险时也很有用。对于cron,您至少必须考虑这一点。在某些情况下,将脚本 at 本身在未来一段时间而不是休眠是有益的。
【解决方案2】:
  1. 为什么不让将构建放入目录的构建过程进行通知? (请参阅SO 3691739 了解其来源!)

  2. cron 运行程序是完全可以接受的 - 并且比带有睡眠的永久循环更简单,虽然不是很多。

  3. 针对 cron 解决方案,由于该过程是简单的一次性,因此您无法判断自上次运行以来发生了什么变化 - 没有状态。 (或者,更准确地说,如果您提供状态 - 可能是通过文件提供 - 与运行在内部保持其状态的单个脚本相比,您的生活要复杂得多。)

  4. 此外,停止通知服务不太明显。如果有一个进程挂在身边,你杀死它并且通知停止。如果通知是由cron 运行的,那么您必须知道它们已用完 crontab,知道它是谁的 crontab,然后编辑该条目以停止它。

  5. 您还应该考虑说服您的公司升级到提供 inotify 机制的 Linux 版本。

【讨论】:

  • 1) 构建过程是单独处理的,几乎不受我控制。 3)实际上存在一种状态,即“缓存”文件存储上次发生更改的时间戳。
  • 感谢您提到我在使用 cron 时无法在程序中使用状态。
【解决方案3】:

如果您使用循环而不是 cron 并希望您的作业定期运行,sleep(300) 往往会漂移。 (考虑脚本其余部分的执行时间)

我建议使用这样的结构:

use constant DELAY => 300;

my $next=time();
while (1){
    $next+=DELAY;

    ...;

    sleep ($next-time());
};

【讨论】:

    【解决方案4】:

    另一种选择是“anacron”实用程序。

    【讨论】:

      【解决方案5】:

      如果您不想使用cron。 这个http://upstart.ubuntu.com/ 可用于保姆进程。 或者你可以使用watch 哪个更容易。

      【讨论】: