3

I'm writing a multi-process program and using a queue to collect the results. After that, I move the results from the queue to a list in the main process (other processes are terminated). Here's the code

import multiprocessing

result = multiprocessing.Queue(maxsize=16)

# the multiprocessing part which fills the Queue with 16 elements

res_list = []
while not result.empty():
    res_list.append(result.get())
print(results.qsize())
print(len(res_list))

I'm expecting

0
16

But the output is

3
13

I also got other numbers such as 4, 12 when running the program several times. Sometimes I do get 0, 16, but this is not guaranteed.

I've read this post: Multiprocessing Queue empty() function not working reliably in python

The answer mentioned that the number that qsize() returns might not be reliable. But I think it is only the number that is not reliable, the queue should actually be emptied. Also, empty() also returns true (so the program jumps out of the while part), so the queue should already be emptied.

However, the res_list only gets 13 elements. So I'm doubting if the queue is really emptied and why this happened. Also, does anyone have any idea about how can I get all my results from the result queue.

Thanks a lot!

5
  • you can get all results with exception handling, do queue.get(block=False) in a loop inside a try...except block. The exception raised, in case the queue is finally empty, will be queue.Empty. That's when you know the queue is actually empty and you can break the loop. As for your question of why this happens, it might just be possible that the feeder process which puts items on the queue is slower. So the queue does get empty, which causes the loop to break, but the feeder process puts more items after that. More context on how the feeder process functions would be helpful here. Commented Aug 12, 2022 at 15:53
  • 1
    q.size, q.full, and q.empty all may be unreliable due to the fact that a thread is handling read/write to the underlying pipe in the background, and no checks are done on the state of that thread. I would almost never rely on them, and consequently almost never use them. They are included for cross compatibility with the non-multiprocessing version of Queue where those calls are reliable (because there's no thread to worry about. I think @Charchit is probably most correct however here that you manage to empty the queue briefly before all the items are put in by the child process. Commented Aug 12, 2022 at 20:44
  • The comments by Charchit and Aaron are correct. The documentation for multiprocessing.Queue.empty says literally: "Because of multithreading/multiprocessing semantics, this is not reliable." So there is no reason for you to think that it is actually reliable in practice. Just don't use it. Commented Aug 13, 2022 at 2:03
  • 1
    @Charchit The loop you suggest only works correctly if you can be sure that the child processes have finished putting items on the queue. But you can only be sure of that if you wait for these child processes to complete by calling join. But the documentation warns of a possible deadlock if you join the child processes before retrieving all the items the child processes have put on the queue. One way to handle this is for each of the N child process to put a sentinel value to the queue as the final item. The main processes does blocking get calls until it has seen N sentinel values. Commented Aug 15, 2022 at 12:15
  • @Charcit Or if, as the comment in the code suggests, that you know how many items will be ultimately put on the queue, i.e. 16, then do 16 blocking calls in the main process to get the items. Either way, joining the child processes must follow getting all the items from the queue and you would have a race condition trying to do this your way in that you could get an Empty exception before all 16 items have been put. Commented Aug 15, 2022 at 12:20

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.