I want to
- call shell commands (for example ‘sleep’ below) in parallel,
- report on their individual starts and completions and
- be able to kill them with ‘kill -9 parent_process_pid’.
There is already a lot written on these kinds of things already but I feel like I haven’t quite found the elegant pythonic solution I’m looking for. I’m also trying to keep things relatively readable (and short) for someone completely unfamiliar with python.
My approach so far (see code below) has been:
- put subprocess.call(unix_command) in a wrapper function that reports the start and completion of the command.
- call the wrapper function with multiprocess.Process.
- track the appropriate pids, store them globally, and kill them in the signal_handler.
I was trying to avoid a solution that periodically polled the processes but I’m not sure why.
Is there a better approach?
import subprocess,multiprocessing,signal
import sys,os,time
def sigterm_handler(signal, frame):
print 'You killed me!'
for p in pids:
os.kill(p,9)
sys.exit(0)
def sigint_handler(signal, frame):
print 'You pressed Ctrl+C!'
sys.exit(0)
signal.signal(signal.SIGINT, sigint_handler)
signal.signal(signal.SIGTERM, sigterm_handler)
def f_wrapper(d):
print str(d) + " start"
p=subprocess.call(["sleep","100"])
pids.append(p.pid)
print str(d) + " done"
print "Starting to run things."
pids=[]
for i in range(5):
p=multiprocessing.Process(target=f_wrapper,args=(i,))
p.daemon=True
p.start()
print "Got things running ..."
while pids:
print "Still working ..."
time.sleep(1)
Once
subprocess.callreturns, the sub-process is done — andcall‘s return value is the sub-process’sreturncode. So, accumulating those return codes in listpids(which btw is not synced between the multi-process appending it, and the “main” process) and sending them9signals “as if” they were process ids instead of return codes, is definitely wrong.Another thing with the question that’s definitely wrong is the spec:
since the
-9means the parent process can’t possibly intercept the signal (that’s the purpose of explicitly specifying-9) — I imagine the-9is therefore spurious here.You should be using
threadinginstead ofmultiprocessing(each “babysitter” thread, or process, does essentially nothing but wait for its sub-process, so why waste processes on such a lightweight task?-); you should also callsuprocess.Processin the main thread (to get the sub-process started and be able to obtain its.pidto put in the list) and pass the resulting process object to the babysitter thread which waits for it (and when it’s done reports and removes it from the list). The list of subprocess ids should be guarded by a lock, since the main thread and several babysitter threads can all access it, and a set would probably be a better choice than a list (faster removals) since you don’t care about ordering nor about avoiding duplicates.So, roughly (no testing, so there might be bugs;-) I’d change your code to s/thing like: