Reputation: 37
I am using multiprocessing to create a child process, then the child process will do some time consuming long time work which may never end.
What I want to do is when the child process finishes one step, it will trigger an event of the parent process or just call some functions.
Here is part of my script:
class WorkerProcess(multiprocessing.Process):
def __init__(self, port, addresslist, result_queue):
multiprocessing.Process.__init__(self)
self.exit = multiprocessing.Event()
self.serialPort = port
self.addressList = addresslist
self.sch = SerialCommunication(self.serialPort, self.addressList)
self.result_queue = result_queue
def run(self):
while not self.exit.is_set():
self.sch.RegularLoadInfo()
self.result_queue.put(self.sch.rawData)
# here trigger event or method in parent process, or let the queue put trigger it
def shutdown(self):
try:
self.sch.stopSerial()
except Exception:
print(Exception)
self.exit.set()
class DataExchange(object):
def __init__(self):
self._serialOn = False
self.workerSerial = None
def get_serialOn(self):
return self._serialOn
def set_serialOn(self, value):
self._serialOn = value
if self.serialOn == True:
result = multiprocessing.Queue()
self.workerSerial = WorkerProcess(self.serialPort, self.addressList, result)
self.workerSerial.daemon = True
self.workerSerial.start()
elif self.serialOn == False:
self.workerSerial.shutdown()
serialOn = property(get_serialOn, set_serialOn)
def OnUpdate(self, event):
# triggered by child process
# do something
pass
Thanks in advance.
Upvotes: 0
Views: 3936
Reputation: 11573
You cannot call a method in another process directly, but you have two possibilities:
You'll need to set up a queue
to communicate from the child to the parent (or a pipe
if you need to communicate both ways) and then make the parent block (run get()
) until the child sends data (runs put()
).
Since you already have set up a queue result
in your code you either want to take this or hand in another queue to the __init__
constructor of WorkerProcess
.
In the parent process do something like this:
result = multiprocessing.Queue()
self.workerSerial = WorkerProcess(self.serialPort, self.addressList, result)
self.workerSerial.daemon = True
self.workerSerial.start()
while True:
event = result.get()
if event is None:
break
if event == 'update':
self.OnUpdate()
self.workerSerial.terminate()
You'll need to define how the child communicates that he sent the last element (aka the "sentinel"), I chose None
in the example code above.
Once the parent gets the sentinel, it runs terminate()
on the child to end it.
If the parent needs to do stuff alongside waiting for the result, you'll need to periodically check if there's stuff in your queue:
# do stuff in parent
if not result.empty():
event = result.get()
# process event as above and terminate if `None`
Upvotes: 2