サブプロセス¶
ソースコード: 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)¶ サブプロセスを作成します。
引数 limit は (
subprocess.PIPEを stdout と stderr に設定した場合の)Process.stdoutとProcess.stderrのためのStreamReaderラッパーのバッファー上限値を設定します。Processのインスタンスを返します。他のパラメータについては
loop.subprocess_exec()を参照してください。バージョン 3.10 で変更: loop パラメータが削除されました。
-
coroutine
asyncio.create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds)¶ シェルコマンド cmd を実行します。
引数 limit は (
subprocess.PIPEを stdout と stderr に設定した場合の)Process.stdoutとProcess.stderrのためのStreamReaderラッパーのバッファー上限値を設定します。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でない場合);EOF に達するまで stdout および stderr からデータを読み出します;
プロセスが終了するまで待ち受けます。
input オプション引数は子プロセスに送信されるデータ (
bytesオブジェクト) です。(stdout_data, stderr_data)のタプルを返します。input を標準入力 stdin nに書き込んでいる時に
BrokenPipeErrorまたはConnectionResetError例外が送出された場合、例外は無視されます。このような条件は、全てのデータが stdin に書き込まれる前にプロセスが終了した場合に起こります。子プロセスの標準入力 stdin にデータを送りたい場合、プロセスは
stdin=PIPEを設定して生成する必要があります。同様に、None以外の何らかのデータを戻り値のタプルで受け取りたい場合、プロセスはstdout=PIPEとstderr=PIPEのいずれかまたは両方を指定して生成しなければなりません。プロセスから受信したデータはメモリ上にバッファーされることに注意してください。そのため、返されるデータのサイズが大きいかまたは無制限の場合はこのメソッドを使わないようにしてください。
-
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 では、このメソッドは
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 はサブプロセスをサポートしていません。
UNIX の child watchers はサブプロセスの終了を待ち受けるために使われます。より詳しい情報については プロセスのウオッチャー を参照してください。
バージョン 3.8 で変更: UNIX では、異なるスレッドから何らの制限なくサブプロセスを生成するために ThreadedChildWatcher を使うようになりました。
現在の子プロセスのウオッチャーが アクティブでない 場合にサブプロセスを生成すると RuntimeError 例外が送出されます。
標準で提供されない別のイベントループ実装の場合、固有の制限がある可能性があります; それぞれの実装のドキュメントを参照してください。
使用例¶
サブプロセスの制御のために 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 を使って書かれた 同様の例 も参照してください。