0

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.

achillesminor
  • 171
  • 1
  • 11

2 Answers2

1

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.

Josh
  • 1,032
  • 2
  • 12
  • 24
  • No, because if you look at the main.py, the user is asked for input, the value is checked and either a 0 or 1 value is then passed into the the classes "can count" variable, which is being shared by the process the class spawns on starting. The logic all the way through is horrid, as if you don't type in the single character the system is looking for it _will_ go into an infinite loop; however, I don't think the lack of checks is what is causing the issue I'm experiencing. – achillesminor Jun 11 '13 at 17:57
1

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
Steve
  • 36
  • 3
  • 1
    Cheers, but is there a reason you are passing the _do_count, and _count variables in to the function and then simply calling them through the class reference? I would assume that if you are using self._do_count you don't need to pass it in as an argument. – achillesminor Jun 13 '13 at 08:40
  • @achillesminor Good spot. The answer is no, that bit is redundant. It's just clumsiness on my part. I've edited my answer to remove the offending code. – Steve Jun 13 '13 at 17:00