2012-01-02 9 views
3

このPythonコードは、Perlスクリプトの細かいデータをパイプします。Pythonを使ってstdin/stdoutをPerlスクリプトに移植するにはどうすればいいですか

import subprocess 
kw = {} 
kw['executable'] = None 
kw['shell'] = True 
kw['stdin'] = None 
kw['stdout'] = subprocess.PIPE 
kw['stderr'] = subprocess.PIPE 
args = ' '.join(['/usr/bin/perl','-w','/path/script.perl','<','/path/mydata']) 
subproc = subprocess.Popen(args,**kw) 
for line in iter(subproc.stdout.readline, ''): 
    print line.rstrip().decode('UTF-8') 

しかし、まずバッファをディスクファイル(/ path/mydata)に保存する必要があります。なお、このようなサブプロセスにPythonコードとパスライン・バイ・ラインのデータをループに掃除機は次のとおり

import subprocess 
kw = {} 
kw['executable'] = '/usr/bin/perl' 
kw['shell'] = False 
kw['stderr'] = subprocess.PIPE 
kw['stdin'] = subprocess.PIPE 
kw['stdout'] = subprocess.PIPE 
args = ['-w','/path/script.perl',] 
subproc = subprocess.Popen(args,**kw) 
f = codecs.open('/path/mydata','r','UTF-8') 
for line in f: 
    subproc.stdin.write('%s\n'%(line.strip().encode('UTF-8'))) 
    print line.strip() ### code hangs after printing this ### 
    for line in iter(subproc.stdout.readline, ''): 
     print line.rstrip().decode('UTF-8') 
subproc.terminate() 
f.close() 

コードは、サブプロセスの最初の行を送信した後のreadlineとハング。この完全に同じコードを完全に使用する他の実行可能ファイルがあります。

私のデータファイルは非常に大きくなる可能性があります(1.5 GB)ファイルに保存せずにデータをパイプする方法はありますか?私は他のシステムとの互換性のためにperlスクリプトを書き直したくありません。

答えて

1

ありがとうsrgerg。私はまた、スレッドソリューションを試してみました。しかし、このソリューションだけでは、常に吊り下げられています。私の前のコードとsrgergのコードの両方には最終的な解決策がありませんでした。あなたのヒントは私に最後のアイデアを与えました。

最終的な解決策は、十分なダミーデータを書き込み、最終的な有効な行をバッファから強制的に削除します。これをサポートするために、stdinに書き込まれた有効な行の数を追跡するコードを追加しました。スレッド化されたループは、出力ファイルを開き、データを保存し、読み取り行が有効な入力行と等しいときに中断します。このソリューションは、どのサイズのファイルに対しても1行ずつ読み書きを行います。

def std_output(stdout,outfile=''): 
    out = 0 
    f = codecs.open(outfile,'w','UTF-8') 
    for line in iter(stdout.readline, ''): 
     f.write('%s\n'%(line.rstrip().decode('UTF-8'))) 
     out += 1 
     if i == out: break 
    stdout.close() 
    f.close() 

outfile = '/path/myout' 
infile = '/path/mydata' 

subproc = subprocess.Popen(args,**kw) 
t = threading.Thread(target=std_output,args=[subproc.stdout,outfile]) 
t.daemon = True 
t.start() 

i = 0 
f = codecs.open(infile,'r','UTF-8') 
for line in f: 
    subproc.stdin.write('%s\n'%(line.strip().encode('UTF-8'))) 
    i += 1 
subproc.stdin.write('%s\n'%(' '*4096)) ### push dummy data ### 
f.close() 
t.join() 
subproc.terminate() 
0

(ちょうどPopen.stdin上)Popen.stdinPopen.stdoutの使用についてのマニュアルに記載された警告を参照してください:

警告:使用communicate()ではなく、.stdin.write.stdout.readまたは.stderr.readへ他のOSパイプバッファが子をいっぱいにしてブロックすることによるデッドロックを回避するプロセス。

一度、観察てきたようにしながら、私は、すべてを一度メモリ内のギガバイト半の文字列を持つことが非常に望ましいことではないことを認識し、しかしcommunicate()を使用して動作すること方法ですOSパイプバッファがいっぱいになると、stdin.write() + stdout.read()ウェイがデッドロック状態になる可能性があります。

communicate()を使用していますか?

1

あなたのコードはラインでブロックしている:EOF(ファイルの終わり)はサブプロセスが終了したときに起こるであろう、到達したときに、この反復が終了することができる唯一の方法であるため、

for line in iter(subproc.stdout.readline, ''): 

。プロセスが終了するまで待つ必要はありませんが、完了した処理が完了するまで待つだけです。

さらに、Chris Morganが既に指摘しているように、バッファリングに関する問題が発生しています。別のquestion on stackoverflowでは、サブプロセスで非ブロック読み取りを行う方法について説明しています。私はあなたの問題にその質問からコードの迅速かつ汚い適応をハッキングしました:

def enqueue_output(out, queue): 
    for line in iter(out.readline, ''): 
     queue.put(line) 
    out.close() 

kw = {} 
kw['executable'] = '/usr/bin/perl' 
kw['shell'] = False 
kw['stderr'] = subprocess.PIPE 
kw['stdin'] = subprocess.PIPE 
kw['stdout'] = subprocess.PIPE 
args = ['-w','/path/script.perl',] 
subproc = subprocess.Popen(args, **kw) 
f = codecs.open('/path/mydata','r','UTF-8') 
q = Queue.Queue() 
t = threading.Thread(target = enqueue_output, args = (subproc.stdout, q)) 
t.daemon = True 
t.start() 
for line in f: 
    subproc.stdin.write('%s\n'%(line.strip().encode('UTF-8'))) 
    print "Sent:", line.strip() ### code hangs after printing this ### 
    try: 
     line = q.get_nowait() 
    except Queue.Empty: 
     pass 
    else: 
     print "Received:", line.rstrip().decode('UTF-8') 

subproc.terminate() 
f.close() 

それはあなたがこのコードに変更を加える必要があります可能性が極めて高いのですが、少なくとも、それはブロックされません。 。

+0

ありがとうございました。私は最終的なコードで答えを加えました – tahoar

関連する問題