Search code examples
python-2.6multiprocess

While loop is breaking passing of values to a variable within a python process


I have been trying to learn how multiprocessing works in python, and have created a very simple script to test my understanding.

Everything seems to work fine, except for the fact that, within a process, none of value assignments that happen after a while loop appear to be completed.

If I replace the while loop with a for loop, or remove it completely, everything seems to work as expected.

Here is the main.py:

from timepieces import Stopwatch

def run():
    watch = Stopwatch()
    watch.start()

    can_count =  0 if (raw_input('Press q to stop and see seconds counted') == 'q') else 1

    watch._can_count.value = can_count

    print watch.get_seconds()

if __name__ == "__main__":
    run() 

And the timepieces.py file (contains class that creates and controls process):

from multiprocessing import Process, Value
import time
import math

class Stopwatch:
    _count_val = None
    _proc = None
    _can_count = None

    def count_seconds(self, can_count, count_val):
        seconds = 0
        count_val.value = 23
        #print can_count.value == 1

        while can_count.value == 1:
            seconds += 1

        count_val.value = seconds

    def start(self):
        self._count_val = Value('i', 0)
        self._can_count = Value('i', 1)

        self._proc = Process(target = self.count_seconds, args = (self._can_count, self._count_val))
        self._proc.start()

    def get_seconds(self):
        return self._count_val.value

Any thoughts are appreciated.


Solution

  • You need to join the child process when your finished with it. Here's a cleaner example of what your trying to achieve. Notice how all of the stuff related to the process is encapsulated out into one class? It makes dealing with threads and process much easier if you can interact with them through a clean interface.

    Here's the main module

    from asynctimer import AsyncTimer
    import time
    
    def run():
        atimer = AsyncTimer()
    
        atimer.start()
    
        print 'initial count: ', atimer.get_seconds();
    
        print 'Now we wait this process,'
        print 'While the child process keeps counting'
    
        time.sleep(3)
    
        print '3 seconds later:', atimer.get_seconds();
    
        atimer.stop()
    
    if __name__ == '__main__':
        run()
    

    Here's the class that handles the child process.

    from multiprocessing import Process, Value
    
    class AsyncTimer():
    
        def __init__(self):
            self._proc = None
            self._do_count = Value('b',True)
            self._count = Value('i', 0)
    
        def _count_seconds(self):
    
            while self._do_count.value:
                self._count.value += 1
    
        def start(self):
            self._proc = Process(target=self._count_seconds)
            self._proc.start()
    
        def stop(self):
            self._do_count.value = False
            self._proc.join()
    
        def get_seconds(self):
            return self._count.value