Reputation: 3230
I have the below three scripts, and when I run main.py file, it spawns child.py which again executes the subchild.py and terminates quicly, subchild.py however keeps executing for a lot of time.
The problem with this is, main.py is blocked at p.communicate() till subchild.py terminates. If I open task manager and kill the running subchild.py main.py immediately returns the output of child.py
So my questions are as below
# main.py file
if __name__ == '__main__':
import subprocess
p = subprocess.Popen(
["python", "child.py"],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE
)
out, _ = p.communicate()
print(out)
# child.py file
if __name__ == '__main__':
import subprocess
print("Child running")
p = subprocess.Popen(["python", "subchild.py"])
print("Child pid - ", p.pid)
exit(1)
# subchild.py file
if __name__ == '__main__':
import time
time.sleep(10000)
Note: I'm trying this on Windows 7 Enterprise. I'm using python3.6.6
Update after comment:
On the main.py I need child.py's pid, stdout, stderr and process object so that I can kill child.py from main.py at any later point if I want to. This code is a small snippet is part of some API which I am building where the user would want the control to kill the process if he wishes to. subprocesses.call or subprocesses.run would not let me get control over the process
object. I also won't have control over what child.py command I will receive as input for main.py, So I need to somehow not wait for the subchild.py and exit immediately with child.py's output as soon as it completes.
Upvotes: 3
Views: 1299
Reputation: 3230
Finally I found the solution to this myself, this seems to be an open issue with python. Would be glad to see this fixed. https://bugs.python.org/issue26731
Upvotes: 1
Reputation: 1350
Right now, child.py will always wait for subchild.py to finish. If you don't need to wait, you can try subprocess.call()
as an alternative in the child.py code. Replace the Popen()
logic with the call()
logic instead.
p = subprocess.call(["python", "subchild.py"])
Here is a reference: https://docs.python.org/2/library/subprocess.html#subprocess.call
An alternative is to keep the code as it is an actually change to using .call()
in the main.py file.
import subprocess
p = subprocess.call(
["python", "child.py"],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE
)
You mentioned you can't use .call() because you'll need to kill it, however this is not the case. Making this change should allow you to:
Upvotes: 1
Reputation: 280181
Your communicate
call doesn't just wait for the child to complete. It first tries to read the entire contents of the child's stdout and stderr.
Even when the child has completed, the parent can't stop reading, because the grandchild inherits the child's stdin, stdout, and stderr. The parent needs to wait for the grandchild to complete, or at least for the grandchild to close its stdout and stderr, before the parent can be sure it's done reading.
Upvotes: 2