-
-
Save jizhilong/6687481 to your computer and use it in GitHub Desktop.
| #!/usr/bin/env python | |
| import multiprocessing | |
| import time | |
| import subprocess, os, signal, sys | |
| def test(s): | |
| while True: | |
| print s | |
| time.sleep(1.5) | |
| def kill_child_processes(signum, frame): | |
| parent_id = os.getpid() | |
| ps_command = subprocess.Popen("ps -o pid --ppid %d --noheaders" % parent_id, shell=True, stdout=subprocess.PIPE) | |
| ps_output = ps_command.stdout.read() | |
| retcode = ps_command.wait() | |
| for pid_str in ps_output.strip().split("\n")[:-1]: | |
| os.kill(int(pid_str), signal.SIGTERM) | |
| sys.exit() | |
| if __name__ == '__main__': | |
| pool = multiprocessing.Pool(processes=4) | |
| result = pool.map_async(test, 'abcd') | |
| signal.signal(signal.SIGTERM, kill_child_processes) | |
| result.get(10000) | |
| pool.close() | |
| pool.join() |
@brando90 you can use psutil and the following code to create a self-cleaning process:
from contextlib import contextmanager
import subprocess
import psutil
@contextmanager
def process(*args, **kwargs):
proc = subprocess.Popen(*args, **kwargs)
try:
yield proc
finally:
for child in psutil.Process(proc.pid).children(recursive=True):
child.kill()
proc.kill()Note that the *args, **kwargs means that process has the same API as subprocess.Popen π
Then you can do:
with process(['mycommand', 'myarg', '--myoption', 'myoptionvalue'], stdout=open('myfile.out.log', 'w')) as proc:
print(proc.pid)
0/0 # even though this throws an exception, the `process` contextmanager will *still* clean up the process correctly@pcattori impressive usage of contextmanager and psutilπ
os.killpg(os.getpid(), signal.SIGTERM)
os.killpg(os.getpid(), signal.SIGTERM)
Best Solution! thanks!
@pcattori impressive usage of contextmanager and psutil π
I second that, thank you very much for sharing this, Pedro. We just added your code snippet to a little package we are currently gardening, to make it reusable by others, see pyveci/pueblo#39. We hope you don't have any objections about it. It was the last addition amongst a few updates happening last month, so it just become part of pueblo-0.0.4, also available on PyPI.
I don't get it, why is the code for something so conceptually simple so complicated?