Gracefully handling keyboard interrupt for Python multi-processing
Question:
I am working on a project which runs two separate python processes. When I do a ctrl + c
to end the program, I would like the program to end gracefully.
I can produce a minimum working version of the code through the following:
from multiprocessing import Process
import os
import sys
import time
class Test:
def __init__(self):
pass
def run(self):
self.process_a = Process(target=self.main, daemon=True)
self.process_b = Process(target=self.other_func, daemon=True)
self.process_a.start()
self.process_b.start()
self.process_a.join()
self.process_b.join()
def main(self):
try:
while True:
print('sending stuff...')
time.sleep(5)
except KeyboardInterrupt:
self.shutdown()
def other_func(self):
while True:
print("do other stuff...")
time.sleep(5)
def shutdown(self):
print("nCTRL+C pressed ...")
print("Shutting Down...")
# os._exit(1)
if __name__ == '__main__':
mytest = Test()
mytest.run()
When performing a keyboard interrupt, I get the error after it prints Shutting Down...
:
Traceback (most recent call last):
File "testing-error.py", line 47, in <module>
mytest.run()
File "testing-error.py", line 18, in run
self.process_a.join()
File "/usr/lib/python3.8/multiprocessing/process.py", line 149, in join
res = self._popen.wait(timeout)
File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 47, in wait
return self.poll(os.WNOHANG if timeout == 0.0 else 0)
File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 27, in poll
pid, sts = os.waitpid(self.pid, flag)
KeyboardInterrupt
In fact, I can further reduce the code down to the following and get the same error:
from multiprocessing import Process
import os
import sys
import time
class Test:
def __init__(self):
pass
def run(self):
self.process_a = Process(target=self.main, daemon=True)
self.process_a.start()
self.process_a.join()
def main(self):
try:
while True:
print('sending stuff...')
time.sleep(5)
except KeyboardInterrupt:
self.shutdown()
def shutdown(self):
print("nCTRL+C pressed ...")
print("Shutting Down...")
# os._exit(1)
if __name__ == '__main__':
mytest = Test()
mytest.run()
Can anyone help me understand what’s going wrong?
Answers:
Both processes are getting CTRL-C so both need to catch it:
import multiprocessing as mp
import os
import sys
import time
class Test:
def __init__(self):
pass
def run(self):
self.process_a = mp.Process(target=self.main, daemon=True)
self.process_a.start()
try:
self.process_a.join()
except KeyboardInterrupt:
print(mp.current_process().name,'got CTRL-C')
def main(self):
try:
while True:
print('sending stuff...')
time.sleep(5)
except KeyboardInterrupt:
print(mp.current_process().name,'got CTRL-C')
if __name__ == '__main__':
mytest = Test()
mytest.run()
Output:
sending stuff...
Process-1 got CTRL-C
MainProcess got CTRL-C
I am working on a project which runs two separate python processes. When I do a ctrl + c
to end the program, I would like the program to end gracefully.
I can produce a minimum working version of the code through the following:
from multiprocessing import Process
import os
import sys
import time
class Test:
def __init__(self):
pass
def run(self):
self.process_a = Process(target=self.main, daemon=True)
self.process_b = Process(target=self.other_func, daemon=True)
self.process_a.start()
self.process_b.start()
self.process_a.join()
self.process_b.join()
def main(self):
try:
while True:
print('sending stuff...')
time.sleep(5)
except KeyboardInterrupt:
self.shutdown()
def other_func(self):
while True:
print("do other stuff...")
time.sleep(5)
def shutdown(self):
print("nCTRL+C pressed ...")
print("Shutting Down...")
# os._exit(1)
if __name__ == '__main__':
mytest = Test()
mytest.run()
When performing a keyboard interrupt, I get the error after it prints Shutting Down...
:
Traceback (most recent call last):
File "testing-error.py", line 47, in <module>
mytest.run()
File "testing-error.py", line 18, in run
self.process_a.join()
File "/usr/lib/python3.8/multiprocessing/process.py", line 149, in join
res = self._popen.wait(timeout)
File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 47, in wait
return self.poll(os.WNOHANG if timeout == 0.0 else 0)
File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 27, in poll
pid, sts = os.waitpid(self.pid, flag)
KeyboardInterrupt
In fact, I can further reduce the code down to the following and get the same error:
from multiprocessing import Process
import os
import sys
import time
class Test:
def __init__(self):
pass
def run(self):
self.process_a = Process(target=self.main, daemon=True)
self.process_a.start()
self.process_a.join()
def main(self):
try:
while True:
print('sending stuff...')
time.sleep(5)
except KeyboardInterrupt:
self.shutdown()
def shutdown(self):
print("nCTRL+C pressed ...")
print("Shutting Down...")
# os._exit(1)
if __name__ == '__main__':
mytest = Test()
mytest.run()
Can anyone help me understand what’s going wrong?
Both processes are getting CTRL-C so both need to catch it:
import multiprocessing as mp
import os
import sys
import time
class Test:
def __init__(self):
pass
def run(self):
self.process_a = mp.Process(target=self.main, daemon=True)
self.process_a.start()
try:
self.process_a.join()
except KeyboardInterrupt:
print(mp.current_process().name,'got CTRL-C')
def main(self):
try:
while True:
print('sending stuff...')
time.sleep(5)
except KeyboardInterrupt:
print(mp.current_process().name,'got CTRL-C')
if __name__ == '__main__':
mytest = Test()
mytest.run()
Output:
sending stuff...
Process-1 got CTRL-C
MainProcess got CTRL-C