I have a process, that needs to perform a bunch of actions “later” (after 10-60 seconds usually). The problem is that those “later” actions can be a lot (1000s), so using a Thread per task is not viable. I know for the existence of tools like gevent and eventlet, but one of the problem is that the process uses zeromq for communication so I would need some integration (eventlet already has it).
What I’m wondering is What are my options? So, suggestions are welcome, in the lines of libraries (if you’ve used any of the mentioned please share your experiences), techniques (Python’s “coroutine” support, use one thread that sleeps for a while and checks a queue), how to make use of zeromq’s poll or eventloop to do the job, or something else.
consider using a priority queue with one or more worker threads to service the tasks. The main thread can add work to the queue, with a timestamp of the soonest it should be serviced. Worker threads pop work off the queue, sleep until the time of priority value is reached, do the work, and then pop another item off the queue.
How about a more fleshed out answer. mklauber makes a good point. If there’s a chance all of your workers might be sleeping when you have new, more urgent work, then a
queue.PriorityQueueisn’t really the solution, although a “priority queue” is still the technique to use, which is available from theheapqmodule. Instead, we’ll make use of a different synchronization primitive; a condition variable, which in python is spelledthreading.Condition.The approach is fairly simple, peek on the heap, and if the work is current, pop it off and do that work. If there was work, but it’s scheduled into the future, just wait on the condition until then, or if there’s no work at all, sleep forever.
The producer does it’s fair share of the work; every time it adds new work, it notifies the condition, so if there are sleeping workers, they’ll wake up and recheck the queue for newer work.