cron 内部如何调度作业?

发布于 2024-09-29 00:13:25 字数 251 浏览 7 评论 0原文

“现代”cron 守护进程如何在内部安排其作业?一些crond过去常常通过at安排运行。那么,在写出 crontab 后, crond: 是否会

  1. 解析 crontab 以获取所有未来事件以及间隔的睡眠?
  2. 每分钟轮询一个聚合的 crontab 数据库以确定当前时间是否与计划模式匹配?
  3. 其他?

谢谢,

How do "modern" cron daemons internally schedule their jobs? Some cronds used to schedule a run every so often via at. So after a crontab is written out, does crond:

  1. Parse the crontab for all future events and the sleep for the intervals?
  2. Poll an aggregated crontab database every minute to determine if the current time matches the schedule pattern?
  3. Other?

Thanks,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怎言笑 2024-10-06 00:13:25

几只蟋蟀听到了这个问题。很好的 RTFC,带有一些离散事件模拟论文和维基百科:

http://en.wikipedia。 org/wiki/Cron#Multi-user_capability

该 cron 使用的算法如下
如下:

  1. 启动时,在主目录中查找名为 .crontab 的文件
    所有帐户持有人。
  2. 对于找到的每个 crontab 文件,确定未来的下一个时间
    每个命令都要运行。
  3. 将这些命令及其对应的命令放在 Franta-Maly 事件列表中
    相应的时间及其“五
    字段”时间说明符。
  4. 进入主循环:
    1. 检查队列头部的任务条目,计算在队列中的距离
      未来它将被运行。
    2. 在这段时间里睡觉。
    3. 醒来并验证正确时间后,执行任务
      队列的头部(在后台)
      具有用户的权限
      创建了它。
    4. 确定将来下次运行此命令的时间和地点
      当时它又回到了事件列表中

A few crickets heard in this question. Good 'ol RTFC with some discrete event simulation papers and Wikipedia:

http://en.wikipedia.org/wiki/Cron#Multi-user_capability

The algorithm used by this cron is as
follows:

  1. On start-up, look for a file named .crontab in the home directories of
    all account holders.
  2. For each crontab file found, determine the next time in the future
    that each command is to be run.
  3. Place those commands on the Franta-Maly event list with their
    corresponding time and their "five
    field" time specifier.
  4. Enter main loop:
    1. Examine the task entry at the head of the queue, compute how far in the
      future it is to be run.
    2. Sleep for that period of time.
    3. On awakening and after verifying the correct time, execute the task at
      the head of the queue (in background)
      with the privileges of the user who
      created it.
    4. Determine the next time in the future to run this command and place
      it back on the event list at that time
浪荡不羁 2024-10-06 00:13:25

我写了一篇博客文章描述它。< br>
其中包含关于如何实现任务调度实用程序的我的想法,例如 CronQuartz

引用那里的相关文本:

  • 我们可以有一个有限的线程池,它将通过从按 job.nextExecutionTime( 优先级) 优先的 PriorityBlockingQueue (线程安全堆)中选取所有任务来执行它们)
  • 这意味着该堆的顶部元素将始终是最快触发的元素。
  • 我们将遵循标准线程池生产者-消费者模式。
  • 我们将有一个线程,该线程将在无限循环中运行,并在使用队列中的新作业后将其提交到线程池。
    我们称之为QueueConsumerThread
void goToSleep(job, jobQueue){
    jobQueue.push(job);
    sleep(job.nextExecutionTime() - getCurrentTime());
}

void executeJob(job, jobQueue){
    threadpool.submit(job); // async call
    if (job.isRecurring()) {
        job = job.copy().setNextExecutionTime(getCurrentTime() + job.getRecurringInterval());
        jobQueue.add(job);
    }
}

@Override
void run(){
    while(true)
    {
        job = jobQueue.pop()
        if(job.nextExecutionTime() > getCurrentTime()){
            // Nothing to do
            goToSleep(job, jobQueue)
        }
        else{
            executeJob(job, jobQueue)
        }
    }
}
  • 将会有一个线程监视 crontab 文件中是否有任何新的作业添加,并将它们推送到队列中。
  • 我们称之为QueueProducerThread
@Override
void run()
{
    while(true)
    {
        newJob = getNewJobFromCrontabFile() // blocking call
        jobQueue.push(newJob)
    }
}
  • 但是,这样做有一个问题:
    • 假设 Thread1 正在睡眠,一小时后会醒来。
    • 与此同时,一个新任务到达,该任务应该每分钟运行一次。
    • 这个新任务要在一小时后才能开始执行。
  • 为了解决这个问题,只要新任务必须比队列中的前面任务运行得早,我们就可以让 ProducerThread 将 ConsumerThread 从睡眠中强制唤醒:
@Override
void run()
{
    while(true)
    {
        newJob = getNewJobFromCrontabFile() // blocking call
        jobQueue.push(newJob)
        if(newJob == jobQueue.peek())
        {
            // The new job is the one that will be scheduled next.
            // So wakeup consumer thread so that it does not oversleep.
            consumerThread.interrupt()
        }
    }
}

请注意,这可能不是 cron 的内部实现方式。
不过,这是我能想到的最优化的解决方案。
它不需要轮询,并且所有线程都会休眠,直到需要执行任何工作为止。

I wrote a blog post describing it.
which contains my thoughts on how to implement task scheduling utilities like Cron or Quartz.

Quoting the relevant text from there:

  • We can have a finite thread-pool which will execute all the tasks by picking them up from a PriorityBlockingQueue (thread-safe heap) prioritized on job.nextExecutionTime().
  • Meaning that the top element of this heap will be always be the one that will fire the soonest.
  • We will be following the standard threadpool producer-consumer pattern.
  • We will have one thread which will be running in an infinite loop and submitting new jobs to the thread pool after consuming them from the queue.
    Lets call it QueueConsumerThread:
void goToSleep(job, jobQueue){
    jobQueue.push(job);
    sleep(job.nextExecutionTime() - getCurrentTime());
}

void executeJob(job, jobQueue){
    threadpool.submit(job); // async call
    if (job.isRecurring()) {
        job = job.copy().setNextExecutionTime(getCurrentTime() + job.getRecurringInterval());
        jobQueue.add(job);
    }
}

@Override
void run(){
    while(true)
    {
        job = jobQueue.pop()
        if(job.nextExecutionTime() > getCurrentTime()){
            // Nothing to do
            goToSleep(job, jobQueue)
        }
        else{
            executeJob(job, jobQueue)
        }
    }
}
  • There will be one more thread which will be monitoring the crontab file for any new job additions and will push them to the queue.
  • Lets call it QueueProducerThread:
@Override
void run()
{
    while(true)
    {
        newJob = getNewJobFromCrontabFile() // blocking call
        jobQueue.push(newJob)
    }
}
  • However, there is a problem with this:
    • Imagine that Thread1 is sleeping and will wake up after an hour.
    • Meanwhile a new task arrives which is supposed to run every minute.
    • This new task will not be able to start executing until an hour later.
  • To solve this problem, we can have ProducerThread wakeup ConsumerThread from its sleep forcefully whenever the new task has to run sooner than the front task in the queue:
@Override
void run()
{
    while(true)
    {
        newJob = getNewJobFromCrontabFile() // blocking call
        jobQueue.push(newJob)
        if(newJob == jobQueue.peek())
        {
            // The new job is the one that will be scheduled next.
            // So wakeup consumer thread so that it does not oversleep.
            consumerThread.interrupt()
        }
    }
}

Note that this might not be how cron is implemented internally.
However, this is the most optimal solution that I can think of.
It requires no polling and all threads sleep until they need to do any work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文