Steve S.
Steve S.

Reputation: 531

Python multiprocessing vs time.sleep on main process hang child process

I'm trying to use the multiprocessing library in python 2.7 and I found the behaviour of time.sleep() function a little bit disturbing. I need to control a timing critical hardware (on Raspberry PI) and my initial goal was to use a process dedicated to this using this library. But I found that putting the main process to sleep (time.sleep) also put the child process to sleep!?!? Is this the normal behaviour or I'm missing something? Here an exemple of code that reproduce my problem :

import time
from multiprocessing import Process, Queue

def child(q_display):

    c = 9999999

    while True:
        data = q_display.get()
        print data
        print c
        c = c - 1

if __name__ == '__main__':
    q_display = Queue()
    p = Process(target=child, args=(q_display,)).start()

    data = 1

    try:
        while True:
            q_display.put(data)
            data = data + 1
            print "MAIN ***********************************"
            time.sleep(1)

    except KeyboardInterrupt:
        print "Keyboard CTRL-C !!!"

The output is this :

MAIN ***********************************
1
9999999
MAIN ***********************************
2
9999998
MAIN ***********************************
3
9999997
MAIN ***********************************
4
9999996
MAIN ***********************************
5
9999995
MAIN ***********************************
6
9999994

But this is what I expected:

MAIN ***********************************
1
9999999
9999998
9999997
9999996
9999995
9999994
9999993
9999992
MAIN ***********************************
2
9999991
9999990
9999989
9999988
9999987
9999986
9999985
9999984
... etc

What is I'm doing wrong?

Upvotes: 2

Views: 2159

Answers (2)

Bas Swinckels
Bas Swinckels

Reputation: 18488

The problem is that Queue.get() blocks until there is some item available in the queue. By passing a timeout parameter to the get() function, and catching the corresponding error (this needs a from Queue import Empty), you can continue doing other stuff in the child process even if the main process did not send anything yet. Change the code in your child function to this:

while True:
    try:
        data = q_display.get(True, timeout=0.1)  # can raise Empty after 0.1 s
        print data
    except Empty:  # queue was empty, next time better
        pass
    print c
    c = c - 1

This seems to do more or less what you want:

MAIN ***********************************
MAIN ***********************************1
9999999
[...]
9999990
2
MAIN ***********************************
9999989
9999988
[...]
9999980
3
MAIN ***********************************
9999979
[...]
9999970
4
MAIN ***********************************
9999969
[...]
9999960
5
MAIN ***********************************
9999959
[...]
9999950
6
Keyboard CTRL-C !!!
9999949
[...]
9999943

Note that the printouts of the main and the child process can get messed up a bit, they are not an accurate way to monitor the exact timing of the events due to buffering issues.

Upvotes: 1

mgrant
mgrant

Reputation: 1031

I think the issue is that you're sleeping in the loop that's putting data into the queue. So there is only one value in the queue before your main process sleeps, and therefore the child can only read one out before it blocks.

Upvotes: 0

Related Questions