# サブプロセス

ソースコード: 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 for `Process.stdout` and `Process.stderr` (if `subprocess.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 for `Process.stdout` and `Process.stderr` (if `subprocess.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()` and `wait()` methods don't have a timeout parameter: use the `wait_for()` function;

  - `subprocess.Popen.wait()` メソッドが同期処理のビジーループとして実装されているのに対して、 `Process.wait()` メソッドは非同期処理です;

  - universal_newlines パラメータはサポートされていません。

  このクラスは スレッド安全ではありません。

  サブプロセスとスレッド 節も参照してください。

  coroutine wait()

    子プロセスが終了するのを待ち受けます。

    `returncode` 属性を設定し、その値を返します。

    注釈

    `stdout=PIPE` または `stderr=PIPE` を使っており、OS パイプバッファがさらなるデータを受け付けるようになるまで子プロセスをブロックするほど大量の出力を生成場合、このメソッドはデッドロックする可能性があります。この条件を避けるため、パイプを使用する場合は `communicate()` メソッドを使ってください。

  coroutine communicate(input=None)

    プロセスとのやりとりを行います:

    1. stdin にデータを送信します (input が `None` でない場合);

    2. EOF に達するまで stdout および stderr からデータを読み出します;

    3. プロセスが終了するまで待ち受けます。

    input オプション引数は子プロセスに送信されるデータ (`bytes` オブジェクト) です。

    `(stdout_data, stderr_data)` のタプルを返します。

    input を標準入力 stdin nに書き込んでいる時に `BrokenPipeError` または `ConnectionResetError` 例外が送出された場合、例外は無視されます。このような条件は、全てのデータが stdin に書き込まれる前にプロセスが終了した場合に起こります。

    子プロセスの標準入力 stdin にデータを送りたい場合、プロセスは `stdin=PIPE` を設定して生成する必要があります。同様に、 `None` 以外の何らかのデータを戻り値のタプルで受け取りたい場合、プロセスは `stdout=PIPE` と `stderr=PIPE` のいずれかまたは両方を指定して生成しなければなりません。

    プロセスから受信したデータはメモリ上にバッファーされることに注意してください。そのため、返されるデータのサイズが大きいかまたは無制限の場合はこのメソッドを使わないようにしてください。

  send_signal(signal)

    子プロセスにシグナル signal を送信します。

    注釈

    On Windows, `SIGTERM` is an alias for `terminate()`. `CTRL_C_EVENT` and `CTRL_BREAK_EVENT` can be sent to processes started with a creationflags parameter which includes `CREATE_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 than `process.stdin.write()`, `await process.stdout.read()` or `await 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 を使って書かれた 同様の例 も参照してください。