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クラスのコンストラクタを参照してください。
-
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()
