33

The Case:

I need to run some commands/script at certain intervals of time and for this I have two options:

  1. set up a cron-job
  2. implement a loop with sleep in the script itself.

Question:

Which is the better option from resource consumption point of view, why? Is cron the better way? Does cron use some kind of triggers or something making it efficient over the other? What procedure does cron use to check and start the jobs?

8 Answers 8

26

Use cron (or anacron).

Cron is designed for running things at intervals. That is the only thing it does, and there has been a lot of work put into cron for many years to make it what it is today.

The chances that you're going to write a better scheduler in your script are effectively nil. Using cron will work better, avoid having unnecessary code in your script and keep your code concise and more maintainable.

Do not reinvent the wheel if you do not have to.

1
  • I couldn't get cron to work with notify-send on wayland. Sleep and systemd do work, though.
    – Pound Hash
    Nov 27, 2022 at 20:25
19

Use cron because it is a better and more standard practice. At least if this is something that will regularly run (not just something you patched together in a minute). cron is a cleaner and more standard way. It's also better because it runs the shell detached from a terminal - no problem with accidental termination and dependencies on other processes.

Regarding the resources: CPU: Both processes sleep - when they sleep, they do not waste CPU. cron wakes up more frequently to check on things, but it does that anyway (no more for your process). And this is negligible load, most daemons wake up occasionally. Memory: You probably have cron running regardless of this process, so this is no overhead at all. However, cron will only start the shell when the script is called, whereas your script remains loaded in memory (a bash process with environment - a few kilobytes, unless you are loading everything in shell variables).

All in all, for resources it doesn't matter.

19

There are already some good answers on cron and sleep performance, but I want to add some kind of feature comparison. (Thanks to @IvanKleshnin for additions in the comments.)

Pro cron:

  • running already on Unix/Linux systems
  • stable and proven
  • designed for background processes
  • runs from system start-up onward, and so will your script, once installed
  • easier entry of long-term cycles (hours, days, weeks)
  • allows complex long-term repeats ("every second Sunday at 5:35 a.m.")
  • processes need resources (esp. RAM) only when running
  • start time is defined by wallclock time, independent of process runtime

Pro sleep:

  • easier to maintain in a script
  • easier for foreground processes
  • allows sleep times shorter and more precise than a minute
  • allows complex sleep/action cycles ("run this part, then sleep 10 seconds, then run the other part and sleep two hours")
  • will not waste CPU cycles to setup and teardown potentially complex objects in memory in each run
3
  • This is the best, most balanced answer by far. More differences to consider: - "Cronned" process will release RAM between runs, "Looped" process will hold it so e.g. for NodeJS it can mean you need permanent 1Gb vs periodic 1Gb - "Cronned" process will setup/teardown objects in memory potentially wasting a lot of CPU cycles. Commens with "there's no difference in CPU" claims are very, very wrong. The whole idea of having servers (vs standalone scripts) is based on this point. Nov 29, 2022 at 10:32
  • Yet another difference is that "cronned" process will have precise # of runs per time period. With "sleep(1000)" you'll have total run time = 1000 + T and therefore non-deterministic # of runs. It might be not important, but worth mentioning. Nov 29, 2022 at 11:08
  • 1
    @IvanKleshnin Thanks for your comments, good points. I added your items to the lists.
    – Dubu
    Nov 30, 2022 at 15:54
6

Does cron use some kind of triggers or something making it efficient over the other?

I have taken a look at cat /proc/`pidof crond`/stack. Having printed it for a few consecutive times I see that crond just sleeps in hrtimer_nanosleep.

>cat /proc/`pidof crond`/stack
[<ffffffff810a0614>] hrtimer_nanosleep+0xc4/0x180
[<ffffffff810a073e>] sys_nanosleep+0x6e/0x80
[<ffffffff8100b072>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff

sleep utility uses the same system call.

>sleep 100 &
[1] 12761
>cat /proc/12761/stack
[<ffffffff810a0614>] hrtimer_nanosleep+0xc4/0x180
[<ffffffff810a073e>] sys_nanosleep+0x6e/0x80
[<ffffffff8100b072>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff

I assume both utilities (crond & sleep) must have low CPU utilization and if you need to imitate cron you definetely can use sleep.

Update. It is better to observe crond's activity with

strace -p `pidof crond`
1
  • Highly underrated answer. Aug 29, 2019 at 4:30
4

The difference comes that as you add more scripts that need to sleep, you will end up with more processes sleeping waiting around, instead of a single process (cron) that wakes up and runs any scheduled scripts which then close till next run. Cron allows one process that is specialized for running other scripts on time, plus cron lets you schedule relatively freely when something should be run, days of the week or month, specific times, or just every 5 minutes etc.

*Just seeing this again made me think of another advantage of cron. All the scripts that run periodically are then in one place, and it's easy to check from there when and how often they will run. Otherwise you have to check individual scripts.

3

The main difference you are looking for is that cron is not running constantly. As explained in man cron:

   cron then wakes up every minute, examining all stored crontabs,  check‐
   ing  each  command  to  see  if it should be run in the current minute.
   When executing commands, any output is  mailed  to  the  owner  of  the
   crontab (or to the user named in the MAILTO environment variable in the
   crontab, if such exists).  The children copies of  cron  running  these
   processes  have their name coerced to uppercase, as will be seen in the
   syslog and ps output.

In other words, cron will only be started once a minute and it will test whether it should be run. Your sleep approach, on the other hand would require your actual sleep command, your shell, your terminal, and the while (or whatever) loop to be running at the same time.

Even if they were launching the same number of processes, cron would be better. It is written precisely for this by people who tend to be very good at their job. It is bound to do a better job of it than a simple shell loop.

2
  • 7
    Both sleep - there is effectively no difference. Your shell that sleeps also wakes up only when the sleep expires. It doesn't use any more CPU than cron. If anything, cron wakes up more frequently because it has to check if anything changed, while your process just sleeps all the time. However, you do get another bash process loaded (in addition to cron, which runs anyway), so it uses a bit more RAM (a few kB).
    – orion
    Mar 11, 2014 at 8:54
  • The above comment is misleading. No difference in sleep behavior - yes. But a script running by cron will setup/teardown, unlike a script that runs in a loop. The latter is a server-like behavior – very different set of pros & cons. Nov 29, 2022 at 10:35
2

There are good and more informed answers already, but I just wanted to point out that with sleep, you have the ability to freeze the process for variable amount of time, say as a function of some other variables.

If I am writing script to check the percentage of battery that remains and notify-send if it is below pre-defined critical level, I can make the script sleep for the amount of time which is a function of current battery level in percentage instead of checking the battery every one or two minute with the help of cron even when I know it was 80% when last checked.

Battery_notify.sh

#!/bin/bash
CRIT=15
while true; do
    # current battery level
    BAT_LEVEL=`acpi -b |grep -Eo "[0-9]+%"|grep -Eo "[0-9]+"`
    interval=$((($BAT_LEVEL -$CRIT) * 120)) # loose estimate of backup time for each percentage of battery charge.
    # Is AC plugged in?
    state=`acpi -b |grep -Eo "[A-Za-z]+harging"` 
    #only notify if not Plugged in
    if [ "$state" = "Discharging" ] ; then
        # is battery below CRIT level?
        if [ $BAT_LEVEL -le $CRIT ]; then
        aplay ~/apert.wav &
        notify-send "Battery-Low!!!" -i /home/bibek/batt.png -t 900
        sleep 100  # nag me each 100 secs untill I plug the thing 
        else
            sleep $interval
        fi
    else
        # if plugged in sleep 
        if [ $BAT_LEVEL -le $CRIT ]; then
            sleep $interval
        else
            # to check if the AC is unplugged before battery gains charge above CRIT.
            sleep 100 
        fi
    fi
    done
1

Using sleep instead of cron for a single job might be more efficient. But since you usually have cron running in any case, making use of it comes for free, or near enough as makes no difference. So unless you are on an otherwise cron-free embedded system, I'd go for cron.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .