当我用python子进程Popen启动进程时,如何关闭stdout-pipe?
我想知道是否有可能关闭通信管道时,杀死一个不同的线程启动的子进程。如果我不调用通信(),那么kill()将按预期工作,在一秒钟而不是五秒钟后终止进程。当我用python子进程Popen启动进程时,如何关闭stdout-pipe?
我发现了类似问题here的讨论,但我没有得到真正的答案。我假设我必须能够关闭管道或者明确地终止子子进程(在本例中为“睡眠”)并杀死它以释放管道。
我也尝试在SO上找到她的答案,但我只找到this和this和this,根据我可以说(?),它并不直接解决此问题。
所以我想要做的事情是能够在第二个线程中运行一个命令并获取其所有输出,但是当我渴望时能够立即杀死它。我可以通过一个文件和尾部或类似的,但我认为应该有一个更好的方式来做到这一点?
import subprocess, time
from threading import Thread
process = None
def executeCommand(command, runCommand):
Thread(target=runCommand, args=(command,)).start()
def runCommand(command):
global process
args = command.strip().split()
process = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE)
for line in process.communicate():
if line:
print "process:", line,
if __name__ == '__main__':
executeCommand("./ascript.sh", runCommand)
time.sleep(1)
process.kill()
这是脚本:
#!/bin/bash
echo "sleeping five"
sleep 5
echo "slept five"
输出
$ time python poc.py
process: sleeping five
real 0m5.053s
user 0m0.044s
sys 0m0.000s
我认为问题在于process.kill()只会杀死直接子进程(bash),而不会杀死bash脚本的子进程。
的问题和解决方案描述如下:
- http://www.doughellmann.com/PyMOTW/subprocess/#process-groups-sessions
- How to terminate a python subprocess launched with shell=True
使用POPEN(...,preexec_fn = os.setsid)来创建一个进程组和OS。 pgkill杀死整个进程组。例如
import os
import signal
import subprocess
import time
from threading import Thread
process = None
def executeCommand(command, runCommand):
Thread(target=runCommand, args=(command,)).start()
def runCommand(command):
global process
args = command.strip().split()
process = subprocess.Popen(
args, shell=False, stdout=subprocess.PIPE, preexec_fn=os.setsid)
for line in process.communicate():
if line:
print "process:", line,
if __name__ == '__main__':
executeCommand("./ascript.sh", runCommand)
time.sleep(1)
os.killpg(process.pid, signal.SIGKILL)
$ time python poc.py
process: sleeping five
real 0m1.051s
user 0m0.032s
sys 0m0.020s
看起来你可能是Python的超粗粒度并行的受害者。更改你的脚本是:
#!/bin/bash
echo "sleeping five"
sleep 5
echo "sleeping five again"
sleep 5
echo "slept five"
然后输出变为:
process: sleeping five
real 0m5.134s
user 0m0.000s
sys 0m0.010s
如果整个脚本运行的时间将是10秒。所以看起来python控制线程在bash脚本休眠之后才会真正运行。同样,如果你改变你的脚本是:
#!/bin/bash
echo "sleeping five"
sleep 1
sleep 1
sleep 1
sleep 1
sleep 1
echo "slept five"
然后输出变为:
process: sleeping five
real 0m1.150s
user 0m0.010s
sys 0m0.020s
总之,你的代码工作逻辑上实现。 :)
在我看来,最简单的方法来做到这一点,并避免多线程问题将是从主线程设置kill标志,并在通信之前在脚本运行线程中检查它,查杀当该标志是True
时的脚本。
实际上,它与阻塞管道有关的问题多于多线程问题。我需要一个不同的线程,以便我可以从某个地方关闭它。如果我从shell中“杀死”它会杀死脚本及其子进程。 Python的kill失败了,因为它似乎希望管道关闭。 – icecream 2009-10-27 06:59:26
当'process.kill()'被调用时,'/ ascript.sh'死亡,但'睡眠5'里面没有。有趣的是,在'。/ ascript.sh'死后,Python不会立即返回。 – 2009-10-26 11:47:07