2

Suppose I'm running a program and each day I want to pause the program after X iterations until the start of the next calendar day. The amount of time the program will have to be paused each day will vary because I do not know when X iterations will be completed on a given day.

Question Is there a simple way to pause the program so that it will restart at the start of the next day E.S.T?

I thought of using the sleep() function. The problem is the interval the program would have to pause each day is different so I can't put in an absolute time value. So I thought conceptually it would something like this might work.

while true 
    # run function until X loops
    # sleep(Minute(tomorrow's date - now())

But I'm not sure how I would get the start of tomorrow's date from Julia or if this is the most efficient approach.

Any thoughts would be greatly appreciated. Thanks!

phntm
  • 511
  • 2
  • 11

2 Answers2

4

Generally I'd recommend using some OS-level scheduler (like cron) for this instead of a long running process, but you can easily figure out the time your program needs to sleep with

julia> DateTime(today()) + Day(1) - now()
52522991 milliseconds
pfitzseb
  • 2,454
  • 9
  • 21
  • Thanks this is great! Sorry just curious what are the upsides of using an OS-level scheduler vs doing something like this natively in Julia? – phntm Jun 15 '21 at 21:10
  • 2
    @phntm Generally, an OS-level scheduler will be much more robust than a Julia process. For instance, they are designed to handle your computer going to sleep or even rebooting. – BallpointBen Jun 15 '21 at 21:43
4

You would normally use cron like @pfitzseb said. However, the simplest nice Julia code could be:

function once_a_time(f, interval)
    repeat = Ref(true) 
    task = @async begin 
        sleep(5) # some calculated time to start
        while repeat[]
            @async f()
            sleep(interval)
        end
    end
    return (;task, repeat)
end

This function will execute f in given fixed intervals regardless of previous assumptions. This code uses green threads so it assumes that f execution time is smaller that the value of interval (or f is just mostly I/O). The function returns a handle to the task as well as reference to the repeat variable so you can stop your scheduler from an outside code.

Let us now test it:

julia> task, rep = once_a_time(()->println("hello ",round(Int,time()) % 1000), 5)
(task = Task (runnable) @0x000000001b69b850, repeat = Base.RefValue{Bool}(true))

julia> hello 347
hello 352
hello 357
hello 362
julia> rep[]=false
false
Przemyslaw Szufel
  • 40,002
  • 3
  • 32
  • 62
  • 1
    Thanks this is great! Sorry a few follow up questions because I'm not very schooled in this. We are returning task and repeat just so we can control the function with outside code correct? If I wanted the task to enter the scheduler queue upon execution of the function I would just do something like "@async while repeat[ ] f()..." without referencing a task variable? Also what does the semicolon operator in front of the task do in the return function? Final question why is it good to add "repeat[]" as condition in the while loop? Won't the loop terminate on it's own if repeat == false? – phntm Jun 15 '21 at 21:08
  • 2
    Yes! we return `repeat` to control with outside code. If you want just to enter the task you remove the first `@async` in my code. The semicolon at `return (; a,b)` returns a `NamedTuple`. We assign `repeat = Ref(true) ` so `repeat[]` yields `true` until we change it in exterrnal code to `false` (see my code). This is how the external control works in my code. – Przemyslaw Szufel Jun 15 '21 at 21:39
  • Got it thanks so much...and just to be clear the code still would work if I removed 'repeat[]' from the line 'repeat[ ] && sleep(interval)' correct? So long as i have 'while repeat[]' i can shut it off with an external code. So the "repeat[]" within the while loop is just a redundancy or does it play some other function? – phntm Jun 16 '21 at 10:47
  • 1
    Yes you can remove `repeat[] &&` from the line `repeat[ ] && sleep(interval)` - I have actually updated my answer because lines after `@async` get executed anyway immedietaly so this `repeat[] &&` was in fact redundant. Thanky you. – Przemyslaw Szufel Jun 16 '21 at 13:40