サブプロセス¶
ソースコード: Lib/asyncio/subprocess.py, Lib/asyncio/base_subprocess.py
このセクションはサブプロセスの生成と管理を行う高水準の async/await asyncio API について説明します。
以下は、 asyncio モジュールがどのようにシェルコマンドを実行し、結果を取得できるかを示す例です:
import asyncio
async def run(cmd):
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
print(f'[{cmd!r} exited with {proc.returncode}]')
if stdout:
print(f'[stdout]\n{stdout.decode()}')
if stderr:
print(f'[stderr]\n{stderr.decode()}')
asyncio.run(run('ls /zzz'))
このサンプルコードは以下を出力します:
['ls /zzz' exited with 1]
[stderr]
ls: /zzz: No such file or directory
全ての asyncio のサブプロセス関数は非同期ですが、 asyncio モジュールはこれらの非同期関数と協調するための多くのツールを提供しているので、複数のサブプロセスを並列に実行して監視することは簡単です。実際、上記のサンプルコードを複数のコマンドを同時に実行するように修正するのはきわめて単純です:
async def main():
await asyncio.gather(
run('ls /zzz'),
run('sleep 1; echo "hello"'))
asyncio.run(main())
使用例 節も参照してください。
サブプロセスの生成¶
- coroutine asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
サブプロセスを作成します。
The limit argument sets the buffer limit for
StreamReader
wrappers forProcess.stdout
andProcess.stderr
(ifsubprocess.PIPE
is passed to stdout and stderr arguments).Process
のインスタンスを返します。他のパラメータについては
loop.subprocess_exec()
を参照してください。バージョン 3.10 で変更: loop パラメータが削除されました。
- coroutine asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
シェルコマンド cmd を実行します。
The limit argument sets the buffer limit for
StreamReader
wrappers forProcess.stdout
andProcess.stderr
(ifsubprocess.PIPE
is passed to stdout and stderr arguments).Process
のインスタンスを返します。他のパラメータについては
loop.subprocess_shell()
のドキュメントを参照してください。重要
シェルインジェクション の脆弱性を回避するために全ての空白文字および特殊文字を適切にクオートすることは、アプリケーション側の責任で確実に行ってください。シェルコマンドを構成する文字列内の空白文字と特殊文字のエスケープは、
shlex.quote()
関数を使うと適切に行うことができます。バージョン 3.10 で変更: loop パラメータが削除されました。
注釈
サブプロセスは、 ProactorEventLoop
を使えば Windows でも利用可能です。詳しくは Windows におけるサブプロセスのサポート を参照してください。
参考
asyncio は以下に挙げるサブプロセスと協調するための 低水準の API も持っています: loop.subprocess_exec()
, loop.subprocess_shell()
, loop.connect_read_pipe()
, loop.connect_write_pipe()
および Subprocess Transports と Subprocess Protocols。
定数¶
- asyncio.subprocess.PIPE¶
stdin, stdout または stderr に渡すことができます。
PIPE が stdin 引数に渡された場合、
Process.stdin
属性はStreamWriter
インスタンスを指します。PIPE が stdout や stderr 引数に渡された場合、
Process.stdout
とProcess.stderr
属性はStreamReader
インスタンスを指します。
- asyncio.subprocess.STDOUT¶
stderr 引数に対して利用できる特殊な値で、標準エラー出力が標準出力にリダイレクトされることを意味します。
- asyncio.subprocess.DEVNULL¶
プロセスを生成する関数の stdin, stdout または stderr 引数に利用できる特殊な値です。対応するサブプロセスのストリームに特殊なファイル
os.devnull
が使われることを意味します。
サブプロセスとやりとりする¶
create_subprocess_exec()
と create_subprocess_shell()
の2つの関数はどちらも Process クラスのインスタンスを返します。 Process クラスはサブプロセスと通信したり、サブプロセスの完了を監視したりするための高水準のラッパーです。
- class asyncio.subprocess.Process¶
関数
create_subprocess_exec()
やcreate_subprocess_shell()
によって生成された OS のプロセスをラップするオブジェクトです。このクラスは
subprocess.Popen
クラスと同様の API を持つように設計されていますが、いくつかの注意すべき違いがあります:Popen と異なり、 Process インスタンスは
poll()
メソッドに相当するメソッドを持っていません;the
communicate()
andwait()
methods don't have a timeout parameter: use thewait_for()
function;subprocess.Popen.wait()
メソッドが同期処理のビジーループとして実装されているのに対して、Process.wait()
メソッドは非同期処理です;universal_newlines パラメータはサポートされていません。
このクラスは スレッド安全ではありません。
サブプロセスとスレッド 節も参照してください。
- coroutine wait()¶
子プロセスが終了するのを待ち受けます。
returncode
属性を設定し、その値を返します。注釈
stdout=PIPE
またはstderr=PIPE
を使っており、OS パイプバッファがさらなるデータを受け付けるようになるまで子プロセスをブロックするほど大量の出力を生成場合、このメソッドはデッドロックする可能性があります。この条件を避けるため、パイプを使用する場合はcommunicate()
メソッドを使ってください。
- coroutine communicate(input=None)¶
プロセスとのやりとりを行います:
stdin にデータを送信します (input が
None
でない場合);stdin を閉じます;
EOF に達するまで stdout および stderr からデータを読み出します;
プロセスが終了するまで待ち受けます。
input オプション引数は子プロセスに送信されるデータ (
bytes
オブジェクト) です。(stdout_data, stderr_data)
のタプルを返します。input を標準入力 stdin nに書き込んでいる時に
BrokenPipeError
またはConnectionResetError
例外が送出された場合、例外は無視されます。このような条件は、全てのデータが stdin に書き込まれる前にプロセスが終了した場合に起こります。子プロセスの標準入力 stdin にデータを送りたい場合、プロセスは
stdin=PIPE
を設定して生成する必要があります。同様に、None
以外の何らかのデータを戻り値のタプルで受け取りたい場合、プロセスはstdout=PIPE
とstderr=PIPE
のいずれかまたは両方を指定して生成しなければなりません。プロセスから受信したデータはメモリ上にバッファーされることに注意してください。そのため、返されるデータのサイズが大きいかまたは無制限の場合はこのメソッドを使わないようにしてください。
バージョン 3.12 で変更: input=None のときも stdin は閉じられます。
- send_signal(signal)¶
子プロセスにシグナル signal を送信します。
注釈
On Windows,
SIGTERM
is an alias forterminate()
.CTRL_C_EVENT
andCTRL_BREAK_EVENT
can be sent to processes started with a creationflags parameter which includesCREATE_NEW_PROCESS_GROUP
.
- terminate()¶
子プロセスを停止します。
On POSIX systems this method sends
SIGTERM
to the child process.On Windows the Win32 API function
TerminateProcess()
is called to stop the child process.
- kill()¶
子プロセスを強制終了 (kill) します。
POSIX システムの場合、このメソッドは子プロセスに
SIGKILL
シグナルを送信します。Windows では、このメソッドは
terminate()
のエイリアスです。
- stdin¶
標準入力ストリーム (
StreamWriter
) です。プロセスがstdin=None
で生成された場合はNone
になります。
- stdout¶
標準出力ストリーム (
StreamReader
) です。プロセスがstdout=None
で生成された場合はNone
になります。
- stderr¶
標準エラー出力ストリーム (
StreamReader
) です。プロセスがstderr=None
で生成された場合はNone
になります。
警告
Use the
communicate()
method rather thanprocess.stdin.write()
,await process.stdout.read()
orawait process.stderr.read()
. This avoids deadlocks due to streams pausing reading or writing and blocking the child process.- pid¶
子プロセスのプロセス番号 (PID) です。
create_subprocess_shell()
関数によって生成されたプロセスの場合、この属性は生成されたシェルの PID になることに注意してください。
- returncode¶
プロセスが終了した時の終了ステータスを返します。
この属性が
None
であることは、プロセスがまだ終了していないことを示しています。負の値
-N
は子プロセスがシグナルN
により中止させられたことを示します (POSIX のみ)。
サブプロセスとスレッド¶
標準的な asyncio のイベントループは、異なるスレッドからサブプロセスを実行するのをデフォルトでサポートしています。
Windows のサブプロセスは ProactorEventLoop
(デフォルト) のみ提供され、 SelectorEventLoop
はサブプロセスをサポートしていません。
標準で提供されない別のイベントループ実装の場合、固有の制限がある可能性があります; それぞれの実装のドキュメントを参照してください。
使用例¶
サブプロセスの制御のために Process
クラスを使い、サブプロセスの標準出力を読み出すために StreamReader
を使う例です。
サブプロセスは create_subprocess_exec()
関数により生成されます:
import asyncio
import sys
async def get_date():
code = 'import datetime; print(datetime.datetime.now())'
# Create the subprocess; redirect the standard output
# into a pipe.
proc = await asyncio.create_subprocess_exec(
sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
# Read one line of output.
data = await proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Wait for the subprocess exit.
await proc.wait()
return line
date = asyncio.run(get_date())
print(f"Current date: {date}")
低水準の API を使って書かれた 同様の例 も参照してください。