我正在尝试使用管道在python中的进程之间进行通信。这些进程将从不同的线程调用,因此可能无法直接访问每个进程的Popen
对象。我在下面写了一个脚本,作为一个简单的概念证明,但发现我的接收过程永远不会终止。
import os
import subprocess
import traceback
import shlex
if __name__ == '__main__':
(fd_out, fd_in) = os.pipe()
pipe_in = os.fdopen(fd_in, 'w')
pipe_out = os.fdopen(fd_out, 'r')
file_out = open('outfile.data', 'w+')
cmd1 = 'cat ' + ' '.join('parts/%s' % x for x in sorted(os.listdir('parts')))
cmd2 = 'pbzip2 -d -c'
pobj1 = subprocess.Popen(shlex.split(cmd1), stdout=pipe_in)
pobj2 = subprocess.Popen(shlex.split(cmd2), stdin=pipe_out,
stdout=file_out)
print 'closing pipe in'
pipe_in.close()
print 'closing pipe out'
pipe_out.close()
print 'closing file out'
file_out.close()
print 'waiting on process 2'
pobj2.wait()
print 'done'
这在很多方面都能正确运行。数据块通过管道传输到第二个进程,第二个进程解压缩流并将其写入文件。我可以看到这些进程,直到它们似乎只是在等待(并且什么也不做),终止第二个进程,文件似乎完全被写入。
所以,我想知道为什么第二个进程永远不会终止。似乎它从未意识到输入流已经关闭。如何正确关闭管道,以便进程知道终止?
david_clymer@zapazoid:/home/tmp/db$ python test.py
closing pipe in
closing pipe out
closing file out
waiting on process 2
^Z
[1]+ Stopped python test.py
david_clymer@zapazoid:/home/tmp/db$ bg
[1]+ python test.py &
david_clymer@zapazoid:/home/tmp/db$ jobs -l
[1]+ 31533 Running python test.py &
david_clymer@zapazoid:/home/tmp/db$ ps -fp 31533
UID PID PPID C STIME TTY TIME CMD
1000 31533 22536 0 15:22 pts/2 00:00:00 python test.py
david_clymer@zapazoid:/home/tmp/db$ lsof |grep $(pwd)
bash 3432 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
bash 22536 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
python 31533 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 david_clymer 1u REG 253,3 12255300000 397270 /home/tmp/db/outfile.data
pbzip2 31535 31536 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 31536 david_clymer 1u REG 253,3 12255300000 397270 /home/tmp/db/outfile.data
pbzip2 31535 31537 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 31537 david_clymer 1u REG 253,3 12255300000 397270 /home/tmp/db/outfile.data
pbzip2 31535 31538 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 31538 david_clymer 1u REG 253,3 12255300000 397270 /home/tmp/db/outfile.data
pbzip2 31535 31539 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 31539 david_clymer 1u REG 253,3 12255300000 397270 /home/tmp/db/outfile.data
pbzip2 31535 31540 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 31540 david_clymer 1u REG 253,3 12255300000 397270 /home/tmp/db/outfile.data
pbzip2 31535 31541 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 31541 david_clymer 1u REG 253,3 12255300000 397270 /home/tmp/db/outfile.data
pbzip2 31535 31542 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 31542 david_clymer 1u REG 253,3 12255300000 397270 /home/tmp/db/outfile.data
pbzip2 31535 31543 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 31543 david_clymer 1u REG 253,3 12255300000 397270 /home/tmp/db/outfile.data
pbzip2 31535 31544 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
pbzip2 31535 31544 david_clymer 1u REG 253,3 12255300000 397270 /home/tmp/db/outfile.data
lsof 31599 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
grep 31600 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
lsof 31602 david_clymer cwd DIR 253,3 483328 408117 /home/tmp/db
david_clymer@zapazoid:/home/tmp/db$ strace -p 31533
Process 31533 attached - interrupt to quit
wait4(31535, ^C <unfinished ...>
Process 31533 detached
我想我正在做一些愚蠢的事。我想知道什么,为什么。
答案 0 :(得分:2)
第二个进程可能是继承管道的输入端,因此永远不会关闭。我不是Python专家,但也许有可能避免这种情况是Popen
先用stdin=PIPE
进行第二个进程,然后Popen
第一个进程使用第二个进程.stdin
1}}作为stdout
。 (Popen
可能会安排进程无法处理它在内部创建的管道的输入端。)
为了解决文件描述符继承问题,请使用close_fds=True
调用子进程:
pobj2 = subprocess.Popen(shlex.split(cmd2),
stdin=pipe_out,
stdout=file_out,
close_fds=True)
答案 1 :(得分:1)
subprocess.Popen()
,您不需要手动调用os.pipe()
等等。
pobj1 = subprocess.Popen(['cat'] + ['parts/' + x for x in sorted(os.listdir('parts'))],
stdout=PIPE)
pobj2 = subprocess.Popen(shlex.split('pbzip2 -d -c'),
stdin=pobj1.stdout,
stdout=open('outfile.data', 'w+'))
应该做你想做的事。