Interruptable Sleep?

169 views Asked by At

I am currently building a python app which should trigger functions at given timestamps entered by the user (not entered in chronological order).
I ran into a problem because I don't want my program to be busy-waiting checking if a new timestamp has been entered that must be added to the timer queue but also not creating a whole bunch of threads for every time a new timestamp is creating with its single purpose waiting for that timestamp.
What I thought of is putting it all together in one thread and doing something like an interruptable sleep, but I can't think of another way besides this:

while timer_not_depleted:
      sleep(1)
      if something_happened:
          break

which is essentially busy-waiting. So any suggestions on realizing an interruptable sleep?

2

There are 2 answers

0
VPfB On

I'd like to suggest select.

Call it with a timeout equal to the delay to the nearest event (heap queue is a good data structure to maintain a queue of future timestamps) and provide a socket (as an item in the rlist arg), where your program listens on for updates from the user.

The select call returns when the socket has incoming data or when the timeout has occurred.

1
Zz'Rot On

Your intuition of using threads is correct. The following master-worker construction can work:

  • The master thread spawns a worker thread that waits for "jobs";
  • The two threads share a Queue - whenever a new job needs to be scheduled, the master thread puts a job specification into the queue;
  • Meanwhile, the worker thread does the following:
    • Maintain a separate list of future jobs to run and keep track of how long to keep sleeping until the next job runs;
    • Continue listening to new jobs by calling Queue.get(block=True, timeout=<time-to-next-job>);
    • In this case, if no new jobs are scheduled until the timeout, Queue.get will raise Empty exception - and at this point the worker thread should run the scheduled function and get back to polling. If a new job is scheduled in the meantime, Queue.get returns the new job, such that you can update the timeout value and then get back to waiting.