Python subprocess模块:循环遍历子进程的stdout
我有一些命令是通过subprocess模块来运行的。然后我想逐行处理输出的内容。文档上说不要使用data_stream.stdout.read,我并没有这样做,但我可能在做其他事情时间接调用了这个。我的输出处理方式是这样的:
for line in data_stream.stdout:
#do stuff here
.
.
.
这样做会导致死锁吗?比如说从data_stream.stdout读取数据,还是说Popen模块已经为这种循环处理做好了准备,它会使用communicate的代码,并为你处理所有的调用?
4 个回答
4
SilentGhost和chrispy的回答适合处理小到中等量的子进程输出。不过,有时候输出可能会很多,甚至多到无法在内存中轻松存储。这种情况下,应该先用start()
启动进程,然后创建几个线程:一个线程负责读取child.stdout
(标准输出),另一个线程负责读取child.stderr
(错误输出),这里的child
就是子进程。最后,你需要用wait()
来等待子进程结束。
其实,这就是communicate()
的工作原理;使用自己创建的线程的好处是,你可以在子进程生成输出时就开始处理这些输出。例如,在我的项目python-gnupg
中,我用这种方法实时读取GnuPG可执行文件的状态输出,而不是等到所有输出都生成后再调用communicate()
。你可以查看这个项目的源代码,相关内容在gnupg.py
模块中。
9
如果你在和子进程进行通信,也就是说你同时在写入标准输入(stdin)和读取标准输出(stdout),那么你就得小心死锁的问题。因为这些管道可能会被缓存,所以这种双向通信是非常不推荐的:
data_stream = Popen(mycmd, stdin=PIPE, stdout=PIPE)
data_stream.stdin.write("do something\n")
for line in data_stream:
... # BAD!
不过,如果在创建数据流的时候你没有设置标准输入(stdin)或者标准错误(stderr),那么就没问题了。
data_stream = Popen(mycmd, stdout=PIPE)
for line in data_stream.stdout:
... # Fine
如果你需要双向通信,可以使用communicate这个方法。