I have a class called _NodeProcess
. It consists of a mainloop (main
function) which is run in a separate process and methods (start
and stop
) that control the mainloop. Here's the code:
class _NodeProcess:
def __init__(self, master):
self.master = master
self.process = multiprocessing.Process(target=self.main)
self.is_alive = True
self.is_dead = False
def start(self):
self.process.start()
def stop(self):
self.is_alive = False
while not self.is_dead:
pass
def main(self):
while self.is_alive:
task = self.master.give_task()
self.master.grab_result({'header': 'result', 'result': self.master.function(task), 'task': task})
self.is_dead = True
The part that worries me is the stop
function. On each mainloop iteration, I check whether I should continue (self.is_alive == True
), and if I shouldn't, I stop and do self.is_dead = True
to confirm that i had quit the loop. Meanwile, in the stop
function, after setiing self.is_alive
to False
, and block until self.is_dead == True
.
My concern is the way in which I block:
while not self.is_dead:
pass
I'm afraid it may eat to much resources just iterating over that loop at a very high speed. So, I considered another option, using time.sleep
:
import time
while not self.is_dead:
time.sleep(1)
But it doesn't seem like a best way to block until some condition is met (I need an extra library; I lose 0.5 seconds on average when I call the stop
method, if I make the period less, I spend more resources, so it's some kind of a compromise, which has to be made each time I write code like that). Is there a better solution for this particular problem, or maybe it's better to redesign the class in some way that would allow not facing this problem at all?
2 Answers 2
You don't need a self.is_dead
. You simply need to block until the thread is complete. For that, we have join()
:
def stop(self):
self.is_alive = False
self.process.join()
I must preface with the fact that I know little about multiprocessing. However, I do know that for a while
loop of that format using time
, it doesn't particularly matter what you set it to.
On my system, the code:
While 1:
time.sleep(.1)
still uses an undetectable (0.0%) amount of CPU, in comparison with time.sleep(1)
. Even time.sleep(.01)
only uses .4% of my CPU. There are likely better solutions that have to do specifically with that library, but this is likely the simplest.
-
\$\begingroup\$ Yes, it does use a little cpu, and really works, but the problem that bothered me was that I have to choose the time. And I have no idea how to choose between 0.1 and 0.01 for example, so, when I finally write some number in there, I can't be sure I chose the right one. That doesn't feel as a good programming practice:) And also, I have to import an extra library, which is also not so great. \$\endgroup\$Ilya Peterov– Ilya Peterov2015年10月28日 13:45:25 +00:00Commented Oct 28, 2015 at 13:45
multiprocessing.Lock
and/ormultiprocessing.Condition
. Playing withtime.sleep()
is an anti-pattern. \$\endgroup\$self.process.join()
and to me it seems the best solution in this particular situation (waiting for thread to finish), though, thank you for your adivice, now I see I need to learn more about thread synchronization, because in a common situation when I need to wait for some other thing to happen, I'll need it. Thanks:) \$\endgroup\$