I suggest to put a sentinel value to put on the end of the queue
def put_tasks(q):
...
print('put_tasks: no more tasks')
q.put(end_of_queue)
def work(id, q):
while True:
task = q.get()
if task == end_of_queue:
q.put(task)
print("DONE")
return
print('process %d: %s' % (id, task))
time.sleep(.1)
print('process %d: done' % id)
class Sentinel:
def __init__(self, id):
self.id = id
def __eq__(self, other):
if isinstance(other, Sentinel):
return self.id == other.id
return NotImplemented
if __name__ == '__main__':
q = Queue(2)
end_of_queue = Sentinel("end of queue")
task_gen = Process(target=put_tasks, args=(q,))
processes = [Process(target=work, args=(id, q)) for id in range(0, 3)]
...
I don't seem to be able to use object()
as the sentinel because the threads seem to have access different instances, so they don't compare equal.
If you ever wish to generate random sentinels you can use the uuid
module to generate random ids:
import uuid
class Sentinel:
def __init__(self):
self.id = uuid.uuid4()
def __eq__(self, other):
if isinstance(other, Sentinel):
return self.id == other.id
return NotImplemented
Finally, zch used None
for a sentinel which is perfectly adequate as long as the queue cannot have None
in. The sentinel method will work for mostly-arbitrary arguments.