在subprocess.Popen中关闭stdin
假设我写了一个函数。现在的问题是,另一个函数需要用到 voronoi.out 这个文件作为输入。我不知道的是,在 sp.Popen 完成后,怎么才能关闭这个 stdin。如果不关闭的话,qvoronoi 程序会一直“挂着”,直到我的脚本结束,这样下一个函数就无法读取 voronoi.out 文件了。
def voronoi(self):
''' This function calls qvoronoi program to create
file with vertices.'''
self.inp=open(self.out_name, 'r') #Redirect input and output for qvoronoi script
self.out=open('voronoi.out', 'w')
sp.Popen(['./qvoronoi', 'p', 'FN'], stdin=self.inp, stdout=self.out) #Execute qvoronoi
self.out.close() #Safely close output file
2 个回答
2
在子进程启动之前,有可能关闭它的标准输入(stdin):
from sys import stdin
import subprocess
subprocess.run(cmd, preexec_fn=stdin.close)
这样做并不会真正“关闭”标准输入,但可以确保标准输入是一个空文件,而且在Windows系统上也能正常工作:
subprocess.run(cmd, stdin=subprocess.DEVNULL)
这两种解决方案都避免了其他答案中提到的竞争条件。很多命令在启动时会检查标准输入,并根据检查结果改变它们的行为,所以如果在启动后才关闭标准输入,可能会导致一些不可预测的结果。
3
主要的问题是你没有等程序结束就退出了。qvoronio在你的函数结束时仍在使用文件,这样其他程序可能会被阻塞。而且因为你没有等待,qvoronio在执行完后会处于一种“僵尸”状态,看起来就像是卡住了一样。另外,你把临时的输入/输出文件句柄放在了你的对象上,但其实你应该马上关闭它们。
一些更热衷于Python的人喜欢使用上下文管理器来确保文件能正确关闭,可能会这样做:
def voronoi(self):
with open(self.out_name, 'r') as inp:
with open('voronoi.out', 'w') as outp:
qvoronio = sp.Popen(['./qvoronoi', 'p', 'FN'], stdin=inp, stdout=oup)
qvoronio.wait()
注意,等待是在上下文管理器退出后进行的。你在把文件交给子进程后,在父进程中关闭了文件。
我通常会这样做:
def voronoi(self):
qvoronio = sp.Popen(['./qvoronoi', 'p', 'FN'], stdin=open(self.out_name, 'r'),
stdout=open('voronoi.out', 'w'))
qvoronio.wait()
虽然这样做可能会遭到一些纯粹主义者的反对。我的方法在CPython中运行得很好,但在其他版本中可能会遇到问题。