2

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'        

これは多くの点で正しく実行されます。データ チャンクは 2 番目のプロセスにパイプされ、2 番目のプロセスはストリームを解凍してファイルに書き込みます。プロセスが待機しているように見えるまで(そして何もしていないように見えるまで)、2番目のプロセスを終了し、ファイルが完全に書き込まれたように見えるまでプロセスを監視できます。

では、なぜ2番目のプロセスが終了しないのか疑問に思っています。入力ストリームが閉じられたことを認識していないようです。プロセスが終了することを認識できるように、パイプを適切に閉じるにはどうすればよいですか?

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

私は愚かなことをしていると思います。何で、なぜなのか知りたいです。

4

2 に答える 2

2

2 番目のプロセスは、おそらくパイプの入力端を継承しているため、閉じられることはありません。私は Python の専門家ではありませんが、おそらくこれを回避Popenするには、最初に 2 番目のプロセスに を使用しstdin=PIPE、次にPopen最初のプロセスに 2 番目のプロセスを.stdinとして使用しstdoutます。(Popenおそらく、プロセスが内部で作成するパイプの入力端へのハンドルを持たないように調整します。)

ファイル記述子の継承を回避するには、次を使用して subprocess を呼び出しますclose_fds=True

pobj2 = subprocess.Popen(shlex.split(cmd2),
                         stdin=pipe_out,
                         stdout=file_out,
                         close_fds=True)
于 2013-02-13T21:46:54.233 に答える
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+'))

あなたがしたいことをするべきです。

于 2013-02-13T21:49:54.630 に答える