3

Given a pretty standard read/write multithreaded process with a read Queue and a write Queue:

8 times worker done is printed, but the join() statement is never passed. But if I replace queue_out.put(r) by `queue_out.put(1) it works.

This is melting my brain, probably something really stupid. Should I make a copy of my dictionary and put that in the return Queue? Did I make a stupid mistake somewhere?

Process function

def reader(queue_in, queue_out, funktion):
    # Read from the queue
    while True:
        r = queue_in.get()
        if r == 'DONE':
            return
        funktion(r) # funktion adds additional keys to the dictionary
        queue_out.put(r) # <---- replacing r by 1 does let me join()
    print "worker done" # <----- this happens

Populate the input queue

def writer(generator, queue):
    # Write to the queue
    for r in enumerate(generator):
        # r is a complex dictionary
        queue.put(r)    
    print "writer done"
    for _ in range(0, WORKERS):
        queue.put((-1, "DONE"))

The rest

WORKERS = 8

# init Queues
queue_in = Queue()
queue_out = Queue()

# Start processes, with input and output quests
readers = []
for _ in range(0, WORKERS):
    p = Process(target=reader, args=(queue_in, queue_out, funktion))
    p.daemon = True
    p.start()
    readers.append(p)

writer(generator, queue_in)

for p in readers:
    p.join()

print "joined"  # <---- this never happens

queue_in.close()

while not queue_out.empty():
    print queue_out.get()
queue_out.close()
Laurens Koppenol
  • 2,946
  • 2
  • 20
  • 33
  • 1
    I'm curious: what happens when you simply remove `join()`? I always run into this issue when using `Queue()` to communicate between processes and never managed to properly get my head around what's happening. Somewhere I seem to remember reading that `join()` was implicit with `Queue()` but then I lost the reference. Anyway, I run fine without join when using the queue, but `join()` works fine for `Manager.dict()` or `Manager.list()` – roganjosh Oct 06 '16 at 13:54
  • you are my hero. please write your answer as answer – Laurens Koppenol Oct 06 '16 at 13:59
  • 1
    If you don't mind, I'd rather leave it open for a little while before I put an answer. Truth is, I don't know why this happens (the docs seem to suggest that join is standard practice) and I'd rather understand what's going on than get the reps; leaving it open for a bit might mean someone else can shed some proper light on this. Btw, are you on Windows as OS? – roganjosh Oct 06 '16 at 14:03
  • yes Windows & Python 2.7 – Laurens Koppenol Oct 06 '16 at 14:08
  • 1
    Same setup as me then. Let's see if you get something definitive as an answer :) The `multiprocessing` documentation is the most confusing of any module I've used, not helped by the fact that most examples involve something that could be done in the blink of an eye without multiprocessing in the first place! – roganjosh Oct 06 '16 at 14:11
  • I have added a duplicate flag purely because I found the source of the implicit join. I think this is better than adding another answer to this type of question. – roganjosh Oct 06 '16 at 14:52
  • This question is not about what join is doing, but about its very unexpected behavior in this case – Laurens Koppenol Oct 06 '16 at 14:55

1 Answers1

2

I think I have pieced this together from two sources as I always have the same problem. I think the important thing is that this is in Windows.

Note from the documentation

Since Windows lacks os.fork() it has a few extra restrictions:

Then read the answers here that join() is for forked processed.

I have always managed to run multiprocessing in a similar fashion to you without using join() and not seen any errors - I'm more than happy for a counterexample to explain why it's needed. Indeed, removing it has corrected your issue.

And this article goes into more depth about the differences with child processes in multiprocessing between operating systems. I do think that the issue with join(), specifically, should be more explicit in the documentation.

Community
  • 1
  • 1
roganjosh
  • 12,594
  • 4
  • 29
  • 46