2017-01-04 58 views
0

私はGphoto2を使ってDSLRで写真を撮影しています。 bashコマンドに基づいて私はsubprocess.communicateを使用しようとしましたが、カメラが写真を撮った後にフリーズします。出力を読むときにPythonのサブプロセスがフリーズする

端末でgphoto2 --capture-image-and-downloadを試してみると、2秒以下で完了します。私はラズベリーパイに取り組んでいます。

コード:

import subprocess 

class Wrapper(object): 

    def __init__(self, subprocess): 
     self._subprocess = subprocess 

    def call(self,cmd): 
     p = self._subprocess.Popen(cmd, shell=True, stdout=self._subprocess.PIPE, stderr=self._subprocess.PIPE) 
     out, err = p.communicate() 
     return p.returncode, out.rstrip(), err.rstrip() 


class Gphoto(Wrapper): 
    def __init__(self, subprocess): 
     Wrapper.__init__(self,subprocess) 
     self._CMD = 'gphoto2' 

    def captureImageAndDownload(self): 
     code, out, err = self.call(self._CMD + " --capture-image-and-download") 
     if code != 0: 
      raise Exception(err) 
     filename = None 
     for line in out.split('\n'): 
      if line.startswith('Saving file as '): 
       filename = line.split('Saving file as ')[1] 
     return filename 


def main(): 
    camera = Gphoto(subprocess) 

    filename = camera.captureImageAndDownload() 
    print(filname) 

if __name__ == "__main__": 
    main() 

私はこの取得終了した場合:

Traceback (most recent call last): 
    File "test.py", line 39, in <module> 
    main() 
    File "test.py", line 35, in main 
    filename = camera.captureImageAndDownload() 
    File "test.py", line 22, in captureImageAndDownload 
    code, out, err = self.call(self._CMD + " --capture-image-and-download") 
    File "test.py", line 11, in call 
    out, err = p.communicate() 
    File "/usr/lib/python2.7/subprocess.py", line 799, in communicate 
    return self._communicate(input) 
    File "/usr/lib/python2.7/subprocess.py", line 1409, in _communicate 
    stdout, stderr = self._communicate_with_poll(input) 
    File "/usr/lib/python2.7/subprocess.py", line 1463, in _communicate_with_poll 
    ready = poller.poll() 
KeyboardInterrupt 

任意のアイデア?

+1

引用は「最後まで、stdoutとstderrからデータを読みます-of-fileに達しました。 - プロセスが終了していなければ、入力待ちの状態になります。あなたのプロセスは完了していますか? – Torxed

+0

私はかなり確信しています。カメラのシャッターが聞こえ、ファイルが生成されます。一度私はそれが少なくとも5分間座っても、まだフリーズ...私はターミナルでプロセスをテストし、それ以上の入力なしで動作します。 – Dennis

+0

これに似たものを試してみてください。https://gist.github.com/anonymous/0811f71ca0b290f2625c9ba768bd45fd – Torxed

答えて

0

上記のコメントに基づいて、私たちが思いついたことがあります。 .communicate()コールはプログラムをハングアップさせました。実行されたコマンドが適切に終了しなかったため、疑いの余地がありました。

これを回避するために使用できることの1つは、処理が完了したら手動でポーリングして、出力を印刷することです。
上記の要点は電話で書かれているため、これを適切に使用していませんでしたが、実際にコマンドをポーリングして出力をキャッチするためのサンプルコードがあります。

import subprocess 
from time import time 
class Wrapper(): 
    def call(self, cmd): 
     p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
     O = '' 
     E = '' 
     last = time() 
     while p.poll() is None: 
      if time() - last > 5: 
       print('Process is still running') 
       last = time() 
      tmp = p.stdout.read(1) 
      if tmp: 
       O += tmp 
      tmp = p.stderr.read(1) 
      if tmp: 
       E += tmp 
     ret = p.poll(), O+p.stdout.read(), E+p.stderr.read() # Catch remaining output 
     p.stdout.close() # Always close your file handles, or your OS might be pissed 
     p.stderr.close() 
     return ret 

3つの重要な事柄は、悪い危険なとトリッキーかもしれないshell=Trueを使用して、通知に。
私は物事を実行するときにユーザー入力や「不明な変数」を扱うことはほとんどないので、私は個人的に好意的です。しかし、いくつか注意して - 絶対使用しないでください!あなたがエラーと通常の出力を分離する必要がない場合

第二ビーイング、あなたも行うことができます。

Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 

は、それはあなたを心配する一つ少なくファイルハンドルを与えます。

最後に、常にバッファを空にして、常にそれらを閉じます。これらの2つのことが重要です。
空にしないと、アプリケーションがいっぱいになってアプリケーションがハングする可能性があり、Popenはそれ以上のデータを入れることができないため、待機することがあります。
2番目にファイルハンドルをクローズしていないと、開いているファイルハンドルが不足してOSがレンダリングされる可能性があります(特定の時点でOSが開く可能性のある集合ファイルハンドルがあるため、あなたのOSは少し役に立たない)。

ノート:あなたはPython2または3、p.stdout.read()を使用している場合によってはあなたを与えるかもしれないO = ''はなくO = b''などでなければなりません意味、バックデータをバイト)

関連する問題