目次

前のトピックへ

18.4. signal — 非同期イベントにハンドラを設定する

次のトピックへ

18.6. asyncore — 非同期ソケットハンドラ

このページ

18.5. popen2 — アクセス可能な I/O ストリームを持つ子プロセス生成

バージョン 2.6 で撤廃: このモジュールは時代遅れです。:mod:subprocess モジュールを利用してください。 特に 古い関数を subprocess モジュールで置き換える 節を参照してください。

このモジュールにより、Unix および Windows でプロセスを起動し、その入力/出力/エラー出力パイプに接続し、そのリターンコード を取得することができます。

subprocess モジュールが、新しいプロセスを起動してその結果を受け取るためのより強力な仕組みを持っています。 popen2 モジュールよりも subprocess モジュールを利用することが推奨されます。

このモジュールで提供されている第一のインタフェースは 3 つのファクトリ関数です。これらの関数のいずれも、 bufsize を指定した場合、 I/O パイプのバッファサイズを決定します。 mode を指定する場合、文字列 'b' または 't' でなければなりません; Windows では、ファイルオブジェクトをバイナリあるいはテキストモードのどちらで開くかを決めなければなりません。 mode の標準の値は 't' です。

Unixでは cmd はシーケンスでもよく、その場合には (os.spawnv() のように)引数はプログラムシェルを経由せず直接渡されます。 cmd が文字列の場合、(os.system() のように)シェルに渡されます。

子プロセスからのリターンコードを取得するには、 Popen3 および Popen4 クラスの poll() あるいは wait() メソッドを使うしかありません; これらの機能は Unixでしか利用できません。この情報は popen2()popen3() 、および popen4() 関数、あるいは os モジュールにおける同等の関数の 使用によっては得ることができません。 (os モジュールの関数から返されるタプルは popen2 モ ジュールの関数から返されるものとは違う順序です。)

popen2.popen2(cmd[, bufsize[, mode]])

cmd をサブプロセスとして実行します。ファイルオブジェクト (child_stdout, child_stdin) を返します。

popen2.popen3(cmd[, bufsize[, mode]])

cmd をサブプロセスとして実行します。ファイルオブジェクト (child_stdout, child_stdin, child_stderr) を返します。

popen2.popen4(cmd[, bufsize[, mode]])

cmd をサブプロセスとして実行します。ファイルオブジェクト (child_stdout_and_stderr, child_stdin).

バージョン 2.0 で追加.

Unixでは、ファクトリ関数によって返されるオブジェクトを定義しているクラスも利用することができます。これらのオブジェクトは Windows 実装 で使われていないため、そのプラットフォーム上で使うことはできません。

class popen2.Popen3(cmd[, capturestderr[, bufsize]])

このクラスは子プロセスを表現します。通常、 Popen3 インスタンスは上で述べた popen2() および popen3() ファクトリ関数を使って生成されます。

Popen3 オブジェクトを生成するためにいずれかのヘルパー関数を使っていないのなら、 cmd パラメタは子プロセスで実行する シェルコマンドになります。 capturestderr フラグが真であれば、このオブジェクトが子プロセスの標準エラー出力を捕獲しなければならない ことを意味します。標準の値は偽です。 bufsize パラメタが存在する場合、子プロセスへの/からの I/O バッファのサイズを指定します。

class popen2.Popen4(cmd[, bufsize])

Popen3 に似ていますが、標準エラー出力を標準出力と同じファイルオブジェクトで捕獲します。このオブジェクトは通常 popen4() で生成されます。

バージョン 2.0 で追加.

18.5.1. Popen3 および Popen4 オブジェクト

Popen3 および Popen4 クラスのインスタンスは以下のメソッドを持ちます:

Popen3.poll()

子プロセスがまだ終了していない際には -1 を、そうでない場合にはステータスコード (wait() を参照) を返します。

Popen3.wait()

子プロセスの状態コード出力を待機して返します。状態コードでは子プロセスのリターンコードと、プロセスが exit() によって 終了したか、あるいはシグナルによって死んだかについての情報を符号化しています。状態コードの解釈を助けるための関数は os モジュールで定義されています; プロセス管理 節の W*() 関数ファミリを参照してください。

以下の属性も利用可能です:

Popen3.fromchild

子プロセスからの出力を提供するファイルオブジェクトです。 Poepn4 インスタンスの場合、この値は標準出力と標準 エラー出力の両方を提供するオブジェクトになります。

Popen3.tochild

子プロセスへの入力を提供するファイルオブジェクトです。

Popen3.childerr

コンストラクタに capturestderr を渡した際には子プロセスからの標準エラー出力を提供するファイルオブジェクトで、そうでない場合 None になります。 Popen4 インスタンスでは、この値は常に None になります。

Popen3.pid

子プロセスのプロセス番号です。

18.5.2. フロー制御の問題

何らかの形式でプロセス間通信を利用している際には常に、制御フローについて注意深く考える必要があります。これはこのモジュール (あるいは os モジュールにおける等価な機能) で生成されるファイルオブジェクトの場合にもあてはまります。

親プロセスが子プロセスの標準出力を読み出している一方で、子プロセスが大量のデータを標準エラー出力に書き込んでいる場合、この子プロセスから 出力を読み出そうとするとデッドロックが発生します。同様の状況は読み書きの他の組み合わせでも生じます。本質的な要因は、一方のプロセスが別の プロセスでブロック型の読み出しをしている際に、 _PC_PIPE_BUF バイトを超えるデータがブロック型の入出力を行うプロセスによって書き込まれることにあります。

こうした状況を扱うには幾つかのやりかたがあります。

多くの場合、もっとも単純なアプリケーションに対する変更は、親プロセスで以下のようなモデル:

import popen2

r, w, e = popen2.popen3('python slave.py')
e.readlines()
r.readlines()
r.close()
e.close()
w.close()

に従うようにし、子プロセスで以下:

import os
import sys

# note that each of these print statements
# writes a single long string

print >>sys.stderr, 400 * 'this is a test\n'
os.close(sys.stderr.fileno())
print >>sys.stdout, 400 * 'this is another test\n'

のようなコードにすることでしょう。

とりわけ、 sys.stderr は全てのデータを書き込んた後に閉じられなければならないということに注意してください。さもなければ、 readlines() は返ってきません。また、 sys.stderr.close()stderr を閉じないように os.close() を使わなければならないことにも注意してください。 (そうでなく、 sys.stderr に関連付けると、暗黙のうちに閉じられてしまうので、それ以降のエラーが出力されません)。

より一般的なアプローチをサポートする必要があるアプリケーションでは、パイプ経由の I/O を select() ループでまとめるか、個々の popen*() 関数や Popen* クラスが提供する各々のファイルに対して、個別のスレッドを使って読み出しを行います。

参考

Module subprocess
子プロセスの起動と管理のためのモジュール