I would like to have multiple threads performing tasks, but I would also like to get the results in order.
Take a simple sample code:
from threading import Thread
import queue
import time
class TaskQueue(queue.Queue):
def __init__(self, num_workers=1):
queue.Queue.__init__(self)
self.num_workers = num_workers
self.start_workers()
def add_task(self, task, *args, **kwargs):
args = args or ()
kwargs = kwargs or {}
self.put((task, args, kwargs))
def start_workers(self):
for i in range(self.num_workers):
t = Thread(target=self.worker)
t.daemon = True
t.start()
def worker(self):
while True:
##tupl = self.get() # REMOVED
item, args, kwargs = self.get()
item(*args, **kwargs)
self.task_done()
def task(task_num, sleep_time):
time.sleep(sleep_time)
print("Task #{} sleeping {}".format(task_num, sleep_time))
q = TaskQueue(num_workers=2)
for t, s in zip([1,2,3,4,5,6,7,8,9], [9,8,7,6,5,4,3,2,1]):
q.add_task(task, t, s)
q.join() # block until all tasks are done
print("All Done!!")
Where I am adding tasks, with associated task number and each taking different execution time (sleeps).
I have three issues/questions.
1) I am not even getting all the outputs (without even considering the order). Currently I am just getting the output:
Task #4 sleeping 6
Task #2 sleeping 8
Task #6 sleeping 4
Task #8 sleeping 2
Seems I am not getting the odd tasks, maybe everything coming from the other worker. Why is that and how can I get them?
The program just hangs afterwards. I am assuming since the worker blocks until it gets something from the queue. And if the queue is empty, just waits forever. How can I update it so it will quit or hit "All Done!!" once there is no more tasks in the queue.
How can I have it print the tasks in order? Basically I want the results to be:
Task #1 sleeping 9 Task #2 sleeping 8 Task #3 sleeping 7 Task #4 sleeping 6 Task #5 sleeping 5 Task #6 sleeping 4 Task #7 sleeping 3 Task #8 sleeping 2 Task #9 sleeping 1
Also assume the task results are quite large and the number of tasks itself is a lot, thus I dont really want to have them all saved in memory then do some ordering. I should know the number of tasks added into the queue, and would just like to utilize those on what to print first. Saving some in memory temporarily is acceptable. I know in the current example you kind of have to save some first, since the first task takes the longest. You can assume that the execution time (or sleep in this case) will be random per tasks.
Currently using Python 3.7
---EDIT---
Removing tupl = self.get() from the above code solved question #1 and #2. Thus only question #3 is remaining. Any ideas/solution are welcome