18.5.6. サブプロセス¶
ソースコード: Lib/asyncio/subprocess.py
18.5.6.1. Windows でのイベントループ¶
Windows では、デフォルトのイベントループは SelectorEventLoop
になりますが、これはサブプロセスをサポートしていません。代わりに ProactorEventLoop
を使用します。Windows で使用する例:
import asyncio, sys
if sys.platform == 'win32':
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
参考
18.5.6.2. サブプロセスの作成: Process を使用した高水準 API¶
-
coroutine
asyncio.
create_subprocess_exec
(*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)¶ サブプロセスを作成します。
limit 引数で
StreamReader
に渡すバッファリミットを設定します。他の引数についてはAbstractEventLoop.subprocess_exec()
を参照してください。Process
のインスタンスを返します。この関数は コルーチン です。
-
coroutine
asyncio.
create_subprocess_shell
(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)¶ シェルコマンド cmd を実行します。
limit 引数で
StreamReader
に渡すバッファリミットを設定します。他の引数についてはAbstractEventLoop.subprocess_shell()
を参照してください。Process
のインスタンスを返します。シェルインジェクション の脆弱性を回避するために、すべての空白文字およびメタ文字を適切にクオートすることはアプリケーション側の責任です。
shlex.quote()
関数は、シェルコマンドで使用される文字列内の、空白文字とシェルのメタ文字の適切なエスケープに使用できます。この関数は コルーチン です。
パイプに接続するには AbstractEventLoop.connect_read_pipe()
および AbstractEventLoop.connect_write_pipe()
メソッドを使用します。
18.5.6.3. サブプロセスの作成: subprocess.Popen を使用した低水準 API¶
subprocess
モジュールを使用して非同期にサブプロセスを実行します。
-
coroutine
AbstractEventLoop.
subprocess_exec
(protocol_factory, *args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)¶ 1 個以上の文字列引数 (ファイルシステムエンコーディング にエンコードされた文字列またはバイト列) からサブプロセスを作成します。先頭の文字列で実行するプログラムを指定し、残りの文字列でプログラムの引数を指定します (それが Python スクリプトであれば、
sys.argv
の値に相当します)。これは標準ライブラリのsubprocess.Popen
クラスが shell=False で呼び出され、文字列のリストが第 1 引数として渡されたときと似ていますが、Popen
が引数として文字列のリストを 1 個取るのに対し、subprocess_exec()
引数として複数の文字列を取ります。protocol_factory はクラス
asyncio.SubprocessProtocol
のサブクラスを作成しなくてはなりません。その他の引数:
- stdin:
connect_write_pipe()
を使用してサブプロセスの標準入力ストリームに接続されたパイプを表すファイルライクオブジェクト、もしくは定数subprocess.PIPE
(デフォルト) のどちらかになります。 デフォルトでは、パイプが新しく作成され、接続されます。 - stdout:
connect_read_pipe()
, を使用してサブプロセスの標準出力ストリームに接続されたパイプを表すファイルライクオブジェクト、もしくは定数subprocess.PIPE
(デフォルト) のどちらかになります。 デフォルトでは、パイプが新しく作成され、接続されます。 - stderr:
connect_read_pipe()
を使用してサブプロセスの標準エラー出力ストリームに接続されたパイプを表すファイルライクオブジェクト、もしくは定数subprocess.PIPE
(デフォルト) と定数subprocess.STDOUT
のどちらかになります。 デフォルトでは、パイプが新しく作成され、接続されます。subprocess.STDOUT
が指定された場合、サブプロセスの標準エラー出力ストリームは標準出力ストリームと同じパイプに接続されます。 - その他のキーワード引数は、指定してはならない bufsize、universal_newlines および shell を除き、すべて解釈されずに
subprocess.Popen
に渡されます。
(transport, protocol)
のペアを返します。transport はBaseSubprocessTransport
のインスタンスです。このメソッドは コルーチン です。
引数については
subprocess.Popen
クラスのコンストラクタを参照してください。- stdin:
-
coroutine
AbstractEventLoop.
subprocess_shell
(protocol_factory, cmd, *, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)¶ プラットフォームの "シェル" 構文を使用して cmd (ファイルシステムエンコーディング にエンコードされた文字列またはバイト列) からサブプロセスを作成します。これは標準ライブラリ
subprocess.Popen
クラスをshell=True
で呼び出したときと似ています。protocol_factory はクラス
asyncio.SubprocessProtocol
のサブクラスを作成しなくてはなりません。その他の引数についての詳細は
subprocess_exec()
を参照してください。(transport, protocol)
のペアを返します。transport はBaseSubprocessTransport
のインスタンスです。シェルインジェクション の脆弱性を回避するために、すべての空白文字およびメタ文字を適切にクオートすることはアプリケーション側の責任です。
shlex.quote()
関数は、シェルコマンドで使用される文字列内の、空白文字とシェルのメタ文字の適切なエスケープに使用できます。このメソッドは コルーチン です。
18.5.6.4. 定数¶
-
asyncio.subprocess.
PIPE
¶ create_subprocess_shell()
およびcreate_subprocess_exec()
の引数 stdin、stdout あるいは stderr で使用できる特殊な値です。オープンすべき標準ストリームへのパイプを示します。
-
asyncio.subprocess.
STDOUT
¶ create_subprocess_shell()
およびcreate_subprocess_exec()
の引数 stderr で使用できる特殊な値です。標準エラー出力を標準出力と同様に扱うための標準出力へのパイプを示します。
-
asyncio.subprocess.
DEVNULL
¶ create_subprocess_shell()
およびcreate_subprocess_exec()
の引数 stdin、stdout あるいは stderr で使用できる特殊な値です。特殊ファイルos.devnull
を使用するよう示します。
18.5.6.5. Process¶
-
class
asyncio.subprocess.
Process
¶ 関数
create_subprocess_exec()
あるいはcreate_subprocess_shell()
によって作成されたサブプロセスです。Process
クラスの API はsubprocess.Popen
クラスの API に似せて設計されましたが、一部異なります:- 明示的な
poll()
メソッドはありません communicate()
およびwait()
メソッドは timeout 引数を取りません:wait_for()
関数を使用してください- universal_newlines 引数はサポートされません (バイト文字列のみサポートします)
Process
クラスのwait()
メソッドは非同期であるのに対し、Popen
クラスのwait()
メソッドはビジーループとして実装されています。
このクラスは スレッド安全ではありません。 asyncio-subprocess-threads 節を参照してください。
-
coroutine
wait
()¶ プロセスの終了を待ちます。リターンコードが
returncode
属性に設定され、返されます。このメソッドは コルーチン です。
注釈
stdout=PIPE
またはstderr=PIPE
を使用しており、OS パイプバッファのそれ以上のデータを受け取りの待機をブロックするほど子プロセスがパイプに出力した場合、このメソッドはデッドロックします。 これを回避するにはcommunicate()
メソッドを使用してください。
-
coroutine
communicate
(input=None)¶ プロセスと交信、すなわち、標準入力へのデータ送信、EOF に達するまで標準出力および標準エラー出力からのデータ受信、およびプロセスの終了の待機を行います。任意の引数 input は子プロセスに送信するデータを設定します。送信するデータがない場合は
None
を設定します (デフォルト)。input はバイト列でなければなりません。communicate()
は(stdout_data, stderr_data)
のタプルを返します。input を標準入力に書き込んだときに
BrokenPipeError
またはConnectionResetError
例外が送出された場合、例外は無視されます。これは全データが標準入力に書き込まれる前にプロセスが終了したときに発生します。プロセスの標準入力にデータを送りたい場合、
stdin=PIPE
で Process オブジェクトを作成する必要があります。同様に、結果のタプルにNone
以外のものを受け取りたい場合にはstdout=PIPE
および/またはstderr=PIPE
を指定する必要があります。このメソッドは コルーチン です。
注釈
受信したデータはメモリにバッファーされます。そのため、返されるデータが大きいかあるいは制限がないような場合はこのメソッドを使うべきではありません。
バージョン 3.4.2 で変更: このメソッドは
BrokenPipeError
およびConnectionResetError
を無視するようになりました。
-
send_signal
(signal)¶ 子プロセスにシグナル signal を送信します。
注釈
Windows では、
SIGTERM
はterminate()
の別名になります。CTRL_C_EVENT
およびCTRL_BREAK_EVENT
で、creationflags で始まり、CREATE_NEW_PROCESS_GROUP
を含むパラメータをプロセスに送信することができます。
-
terminate
()¶ 子プロセスを停止します。POSIX システムでは、子プロセスに
signal.SIGTERM
を送信します。Windows では、Win32 API 関数TerminateProcess()
が呼び出されます。
-
kill
()¶ 子プロセスを kill します。POSIX システムでは
SIGKILL
を子プロセスに送信します。Windows ではkill()
はterminate()
の別名になります。
-
stdin
¶ 標準入力ストリーム (
StreamWriter
) になります。プロセスがstdin=None
で作成されていた場合None
になります。
-
stdout
¶ 標準出力ストリーム (
StreamReader
) になります。プロセスがstdout=None
で作成されていた場合None
になります。
-
stderr
¶ 標準エラー出力ストリーム (
StreamReader
) になります。プロセスがstderr=None
で作成されていた場合None
になります。
警告
ストリームの読み込みまたは書き込みの一時停止およびプロセスのブロックによるデッドロックを回避するには、
.stdin.write
、.stdout.read
あるいは.stderr.read
ではなく、communicate()
メソッドを使用してください。-
pid
¶ プロセスの識別子です。
create_subprocess_shell()
関数によって作成されたプロセスでは、この属性は生成したシェルのプロセス識別子になる点に注意してください。
-
returncode
¶ プロセスが終了したときのリターンコードです。
None
値はプロセスがまだ終了していないことを示します。負の値
-N
は子プロセスがシグナルN
により中止させられたことを示します (Unix のみ)。
- 明示的な
18.5.6.6. サブプロセスとスレッド¶
asyncio はサブプロセスを異なるスレッドから実行するのをサポートしていますが、制限があります:
- イベントループはメインスレッド内で実行されなければなりません
- 子ウォッチャーは、他のスレッドからサブプロセスが実行される前に、メインスレッドで作成されなければなりません。
メインスレッドで
get_child_watcher()
を呼んで子ウォッチャーをインスタンス化してください。
asyncio.subprocess.Process
クラスはスレッド安全ではありません。
18.5.6.7. サブプロセスの例¶
18.5.6.7.1. トランスポートおよびプロトコルを使用したサブプロセス¶
サブプロセスの出力を取得しサブプロセスの終了を待機するサブプロセスプロトコルの例です。サブプロセスは AbstractEventLoop.subprocess_exec()
メソッドで作成されます:
import asyncio
import sys
class DateProtocol(asyncio.SubprocessProtocol):
def __init__(self, exit_future):
self.exit_future = exit_future
self.output = bytearray()
def pipe_data_received(self, fd, data):
self.output.extend(data)
def process_exited(self):
self.exit_future.set_result(True)
@asyncio.coroutine
def get_date(loop):
code = 'import datetime; print(datetime.datetime.now())'
exit_future = asyncio.Future(loop=loop)
# Create the subprocess controlled by the protocol DateProtocol,
# redirect the standard output into a pipe
create = loop.subprocess_exec(lambda: DateProtocol(exit_future),
sys.executable, '-c', code,
stdin=None, stderr=None)
transport, protocol = yield from create
# Wait for the subprocess exit using the process_exited() method
# of the protocol
yield from exit_future
# Close the stdout pipe
transport.close()
# Read the output which was collected by the pipe_data_received()
# method of the protocol
data = bytes(protocol.output)
return data.decode('ascii').rstrip()
if sys.platform == "win32":
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
date = loop.run_until_complete(get_date(loop))
print("Current date: %s" % date)
loop.close()
18.5.6.7.2. ストリームを使用したサブプロセス¶
サブプロセスを制御する Process
クラスと標準出力から読み込む StreamReader
クラスを使用した例で得す。サブプロセスは create_subprocess_exec()
関数で作成されます:
import asyncio.subprocess
import sys
@asyncio.coroutine
def get_date():
code = 'import datetime; print(datetime.datetime.now())'
# Create the subprocess, redirect the standard output into a pipe
create = asyncio.create_subprocess_exec(sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
proc = yield from create
# Read one line of output
data = yield from proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Wait for the subprocess exit
yield from proc.wait()
return line
if sys.platform == "win32":
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
date = loop.run_until_complete(get_date())
print("Current date: %s" % date)
loop.close()