Python 如何正确关闭两个进程共享的管道?

Python 如何正确关闭两个进程共享的管道?,python,subprocess,pipe,Python,Subprocess,Pipe,我正在尝试使用管道在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,

我正在尝试使用管道在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
david_clymer@zapazoid:/home/tmp/db$python test.py
封闭管道
关闭管道
关闭文件
等待进程2
^Z
[1] +停止python test.py
大卫_clymer@zapazoid:/home/tmp/db$bg
[1] +python test.py&
大卫_clymer@zapazoid:/home/tmp/db$jobs-l
[1] +31533运行python test.py&
大卫_clymer@zapazoid:/home/tmp/db$ps-fp 31533
UID PID PPID C TIME TTY TIME CMD
1000 31533 22536 0 15:22 pts/2 00:00:00 python test.py
大卫_clymer@zapazoid:/home/tmp/db$lsof | grep$(pwd)
bash 3432 david_clymer cwd目录253,3 483328 408117/home/tmp/db
bash 22536 david_clymer cwd目录253,3 483328 408117/home/tmp/db
python 31533 david_clymer cwd目录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
大卫_clymer@zapazoid:/home/tmp/db$strace-p 31533
已连接进程31533-中断以退出
wait4(31535,^C
过程31533分离

我想象我在做一些愚蠢的事情。我想知道是什么,为什么。

第二个进程可能继承了管道的输入端,因此永远不会关闭。我不是Python专家,但也许可以通过
Popen
先用
stdin=pipe
继承第二个进程,然后
Pope来避免这种情况n
第一个进程,第二个进程的
.stdin
作为其
stdout
Popen
可能安排该进程不在其内部创建的管道输入端具有句柄。)

为了解决文件描述符继承问题,请使用
close\u fds=True
调用子流程:

pobj2 = subprocess.Popen(shlex.split(cmd2),
                         stdin=pipe_out,
                         stdout=file_out,
                         close_fds=True)

使用
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+'))

应该做你想做的事。

Ahah!因此,使用
close\u fds=True
解决了这个问题,并使它按预期工作。@vezult谢谢,我不知道close\u fds,但它是有意义的。正如我的记录中所述,Popen对象属性的使用不是一个解决方案,因为它们在单独的线程中不可用。我不知道调用
os.popen()
,所以我不确定您指的是什么。抱歉,我指的是
os.pipe()
。我也不清楚您所说的“调用”是什么意思您原始问题中的一个进程。如果您的意思是希望多个线程能够将输入发送到管道中以供子进程读取,那么对我来说,传递pobject.stdin似乎并不比从描述符打开的文件描述符或流更难。