Question

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.

Was it helpful?

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

OTHER TIPS

I am not sure if you intended this or not, but shouldn't it be

while can_count.value == 1:
    seconds -= 1
    count_val.value = seconds

The way you have it, the loop would never exit, I think. I am still learning python as well so I am not 100% sure.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top