サブプロセス¶
ソースコード: 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())
使用例 節も参照してください。
サブプロセスの生成¶
- async asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
サブプロセスを作成します。
The limit argument sets the buffer limit for
StreamReaderwrappers forstdoutandstderr(ifsubprocess.PIPEis passed to stdout and stderr arguments).Processのインスタンスを返します。他のパラメータについては
loop.subprocess_exec()を参照してください。If the process object is garbage collected while the process is still running, the child process will be killed.
バージョン 3.10 で変更: loop パラメータが削除されました。
- async asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶
シェルコマンド cmd を実行します。
The limit argument sets the buffer limit for
StreamReaderwrappers forstdoutandstderr(ifsubprocess.PIPEis passed to stdout and stderr arguments).Processのインスタンスを返します。他のパラメータについては
loop.subprocess_shell()のドキュメントを参照してください。If the process object is garbage collected while the process is still running, the child process will be killed.
重要
シェルインジェクション の脆弱性を回避するために全ての空白文字および特殊文字を適切にクオートすることは、アプリケーション側の責任で確実に行ってください。シェルコマンドを構成する文字列内の空白文字と特殊文字のエスケープは、
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 に渡すことができます。
If PIPE is passed to stdin argument, the
Process.stdinattribute will point to aStreamWriterinstance.If PIPE is passed to stdout or stderr arguments, the
Process.stdoutandProcess.stderrattributes will point toStreamReaderinstances.
- 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¶
An object that wraps OS processes created by the
create_subprocess_exec()andcreate_subprocess_shell()functions.このクラスは
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 パラメータはサポートされていません。
このクラスは スレッド安全ではありません。
サブプロセスとスレッド 節も参照してください。
- async wait()¶
子プロセスが終了するのを待ち受けます。
returncode属性を設定し、その値を返します。注釈
stdout=PIPEまたはstderr=PIPEを使っており、OS パイプバッファがさらなるデータを受け付けるようになるまで子プロセスをブロックするほど大量の出力を生成場合、このメソッドはデッドロックする可能性があります。この条件を避けるため、パイプを使用する場合はcommunicate()メソッドを使ってください。
- async 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 で変更: stdin gets closed when
input=Nonetoo.
- send_signal(signal)¶
子プロセスにシグナル signal を送信します。
注釈
On Windows,
SIGTERMis an alias forterminate().CTRL_C_EVENTandCTRL_BREAK_EVENTcan be sent to processes started with a creationflags parameter which includesCREATE_NEW_PROCESS_GROUP.
- terminate()¶
子プロセスを停止します。
On POSIX systems this method sends
SIGTERMto the child process.On Windows the Win32 API function
TerminateProcess()is called to stop the child process.
- kill()¶
子プロセスを強制終了 (kill) します。
On POSIX systems this method sends
SIGKILLto the child process.Windows では、このメソッドは
terminate()のエイリアスです。
- stdin¶
Standard input stream (
StreamWriter) orNoneif the process was created withstdin=None.
- stdout¶
Standard output stream (
StreamReader) orNoneif the process was created withstdout=None.
- stderr¶
Standard error stream (
StreamReader) orNoneif the process was created withstderr=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) です。
Note that for processes created by the
create_subprocess_shell()function, this attribute is the PID of the spawned shell.
- 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 を使って書かれた 同様の例 も参照してください。