Help us understand the problem. What is going on with this article?

Python の subprocess で出力を受け取るときは communicate() を使おう

More than 5 years have passed since last update.

ドキュメントに書いてあっても 読んでない or 忘れていた 私のためのメモ。

Pythonで 子プロセスを実行するときには subprocess モジュールを使うことが推奨されています。
その子プロセスの標準出力やエラー出力を受け取るときに、 p.stdout.read()p.stderr.read() を使っていると
子プロセスの出力するデータ量が多い時に 刺さって しまいます。代わりに p.communicate() を使うと良いです。

その件については、下記ドキュメントの中段辺りに
http://docs.python.jp/2.7/library/subprocess.html

警告
stdin.write(), stdout.read(), stderr.read() を利用すると、別のパイプのOSパイプバッファがいっぱいになってデッドロックする恐れがあります。これを避けるためには communicate() を利用してください。

と書かれていますが、うっかり使って(そしてその問題にハマって)いたのでメモです。

以下、簡単な検証コードです。

read()は子プロセスの出力データ量が10KBのときはOKでしたが、100KBのときはダメでした。
communicate()を使えば両方ともOKでした。

spike.py
import subprocess


def bad_impl(cmd):
    print "start bad_impl %s" % cmd
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print "waiting"
    p.wait()
    stdout_data = p.stdout.read()
    stderr_data = p.stderr.read()
    print "finish: %d %d" % (len(stdout_data), len(stderr_data))
    return p.returncode, stdout_data, stderr_data


def better_impl(cmd):
    print "start better_impl %s" % cmd
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print "waiting"
    stdout_data, stderr_data = p.communicate()
    print "finish: %d %d" % (len(stdout_data), len(stderr_data))
    return p.returncode, stdout_data, stderr_data

command1 = "python -c 'print str(1) * 10000'"           # 10KB の出力
command2 = "python -c 'print str(1) * 100000'"          # 100KBの出力

better_impl(command1)
print "=" * 50
bad_impl(command1)
print "=" * 50
better_impl(command2)
print "=" * 50
bad_impl(command2)            # これが失敗する
% python spike.py
start better_impl python -c 'print str(1) * 10000'
waiting
finish: 10001 0
==================================================
start bad_impl python -c 'print str(1) * 10000'
waiting
finish: 10001 0
==================================================
start better_impl python -c 'print str(1) * 100000'
waiting
finish: 100001 0
==================================================
start bad_impl python -c 'print str(1) * 100000'
waiting
↑ここで制御が戻ってこない

更に言えば

communicate() の部分にも以下のような記述があります。

ノート
受信したデータはメモリ中にバッファされます。そのため、返されるデータが大きいかあるいは制限がないような場合はこのメソッドを使うべきではありません。

利用できるメモリ上限を超える場合はこれもダメというわけですね。
その場合は逐次読みだして、ファイルに保存するなりしないといけないわけですね。
そういう数GBのデータを扱うような場合は、その時にまた考えよう… (^^;

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした