サブプロセス
このセクションでは、サブプロセスを作成および管理するための高レベルのasync / await asyncioAPIについて説明します。
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())
例サブセクションも参照してください。
サブプロセスの作成
重要
シェルインジェクションの脆弱性を回避するために、すべての空白文字と特殊文字が適切に引用されていることを確認するのはアプリケーションの責任です。 shlex.quote()関数を使用すると、シェルコマンドの作成に使用される文字列内の空白や特殊なシェル文字を適切にエスケープできます。
ノート
Windows でのデフォルトの非同期イベントループの実装は、サブプロセスをサポートしていません。 ProactorEventLoop が使用されている場合、Windowsではサブプロセスを使用できます。 詳細については、 Windowsでのサブプロセスサポートを参照してください。
も参照してください
asyncioには、サブプロセスを操作するための低レベル APIもあります:loop.subprocess_exec()
、loop.subprocess_shell()
、loop.connect_read_pipe()
、loop.connect_write_pipe()
サブプロセストランスポートおよびサブプロセスプロトコルとして。
定数
- 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()
関数はどちらも、 Process クラスのインスタンスを返します。 Process は、サブプロセスとの通信とその完了の監視を可能にする高レベルのラッパーです。
- class asyncio.subprocess.Process
create_subprocess_exec()
およびcreate_subprocess_shell()
関数によって作成されたOSプロセスをラップするオブジェクト。このクラスは、 subprocess.Popen クラスと同様のAPIを持つように設計されていますが、いくつかの顕著な違いがあります。
Popenとは異なり、Processインスタンスには poll()メソッドに相当するものがありません。
communicate()
およびwait()
メソッドには timeout パラメーターがありません。wait_for()
関数を使用してください。Process.wait()
メソッドは非同期ですが、 subprocess.Popen.wait()メソッドはブロッキングビジーループとして実装されています。Universal_newlines パラメーターはサポートされていません。
このクラスはスレッドセーフではありません。
サブプロセスとスレッドセクションも参照してください。
- send_signal(signal)
シグナル signal を子プロセスに送信します。
ノート
Windowsでは、
SIGTERM
は terminate()のエイリアスです。CTRL_C_EVENT
およびCTRL_BREAK_EVENT
は、CREATE_NEW_PROCESS_GROUP
を含む creationflags パラメーターで開始されたプロセスに送信できます。
- terminate()
子プロセスを停止します。
POSIXシステムでは、このメソッドは signal.SIGTERM を子プロセスに送信します。
Windowsでは、Win32API関数
TerminateProcess()
が呼び出されて、子プロセスが停止します。
- kill()
子供を殺します。
POSIXシステムでは、このメソッドは
SIGKILL
を子プロセスに送信します。Windowsでは、このメソッドは terminate()のエイリアスです。
- stdin
プロセスが
stdin=None
で作成された場合は、標準入力ストリーム( StreamWriter )またはNone
。
- stdout
プロセスが
stdout=None
で作成された場合は、標準出力ストリーム( StreamReader )またはNone
。
- stderr
プロセスが
stderr=None
で作成された場合は、標準エラーストリーム( StreamReader )またはNone
。
警告
process.stdin.write()、 await process.stdout.read()、または await process.stderr.read [ではなく、
communicate()
メソッドを使用してください。 X138X]。 これにより、ストリームが読み取りまたは書き込みを一時停止し、子プロセスをブロックすることによるデッドロックが回避されます。- pid
プロセス識別番号(PID)。
create_subprocess_shell()
関数によって作成されたプロセスの場合、この属性は生成されたシェルのPIDであることに注意してください。
- returncode
プロセスが終了したときの戻りコード。
None
値は、プロセスがまだ終了していないことを示します。負の値
-N
は、子がシグナルN
(POSIXのみ)によって終了したことを示します。
サブプロセスとスレッド
標準の非同期イベントループは、異なるスレッドからのサブプロセスの実行をサポートしますが、制限があります。
- イベントループはメインスレッドで実行する必要があります。
- 子ウォッチャーは、他のスレッドからサブプロセスを実行する前に、メインスレッドでインスタンス化する必要があります。 メインスレッドで get_child_watcher()関数を呼び出して、子ウォッチャーをインスタンス化します。
代替のイベントループ実装は、上記の制限を共有しない場合があることに注意してください。 それらのドキュメントを参照してください。
例
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
if sys.platform == "win32":
asyncio.set_event_loop_policy(
asyncio.WindowsProactorEventLoopPolicy())
date = asyncio.run(get_date())
print(f"Current date: {date}")
低レベルAPIを使用して記述された同じ例も参照してください。