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

标签 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, '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'        

这在很多方面都能正确运行。数据 block 通过管道传输到第二个进程,第二个进程解压缩流并将其写入文件。我可以观察进程,直到它们似乎只是在等待(并且什么都不做),终止第二个进程,并且文件似乎已完全写入。

所以,我想知道为什么第二个进程永远不会终止。它似乎从未意识到输入流已被关闭。如何正确关闭管道,以便进程知道终止?

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

我想我正在做一些愚蠢的事情。我想知道是什么以及为什么。

最佳答案

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

为了解决文件描述符继承问题,请使用 close_fds=True 调用子进程:

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

关于python - 如何正确关闭两个进程共享的管道?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14863530/

相关文章:

python - 如何在 Python 中编写多行乘法条件而不会出现无效语法错误

python - 限制 Tkinter Entry 小部件中的值 : Why can't I delete the first character?

python - Numpy 如何从非均匀分布中采样随机数?

使用 perl 进行格式化的 Python 子进程给出不完整的输出

python - 如何捕获python子进程管道执行中的中间错误

python - 连接/处理脚本到 PySimpleGUI 按钮

linux - 使用 tee 将输入管道输入到两个进程替换

python - Youtube API每个请求或错误返回1个视频

pipe - gnuplot 使用管道输入绘图

linux - 从管道在命令行上创建 zip 时,如何在 zip 中指定文件名?