# サブプロセス

ソースコード: 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 `StreamReader` wrappers for `stdout` and `stderr` (if `subprocess.PIPE` is 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 `StreamReader` wrappers for `stdout` and `stderr` (if `subprocess.PIPE` is 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.stdin` attribute will point to a `StreamWriter` instance.

  If PIPE is passed to stdout or stderr arguments, the `Process.stdout` and `Process.stderr` attributes will point to `StreamReader` instances.

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()` and `create_subprocess_shell()` functions.

  このクラスは `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 パラメータはサポートされていません。

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

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

  async wait()

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

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

    注釈

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

  async communicate(input=None)

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

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

    2. stdin を閉じます;

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

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

    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=None` too.

  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) します。

    On POSIX systems this method sends `SIGKILL` to the child process.

    Windows では、このメソッドは `terminate()` のエイリアスです。

  stdin

    Standard input stream (`StreamWriter`) or `None` if the process was created with `stdin=None`.

  stdout

    Standard output stream (`StreamReader`) or `None` if the process was created with `stdout=None`.

  stderr

    Standard error stream (`StreamReader`) or `None` if the process was created with `stderr=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) です。

    Note that for processes created by the `create_subprocess_shell()` function, this attribute is the PID of the spawned shell.

  returncode

    プロセスが終了した時の終了ステータスを返します。

    この属性が `None` であることは、プロセスがまだ終了していないことを示しています。

    For processes created with `create_subprocess_exec()`, a negative value `-N` indicates that the child was terminated by signal `N` (POSIX only).

    For processes created with `create_subprocess_shell()`, the return code reflects the exit status of the shell itself (e.g. `/bin/sh`), which may map signals to codes such as `128+N`. See the documentation of the shell (for example, the Bash manual's Exit Status) for details.

### サブプロセスとスレッド

標準的な asyncio のイベントループは、異なるスレッドからサブプロセスを実行するのをデフォルトでサポートしています。

Windows のサブプロセスは `ProactorEventLoop` (デフォルト) のみ提供され、 `SelectorEventLoop` はサブプロセスをサポートしていません。

標準で提供されない別のイベントループ実装の場合、固有の制限がある可能性があります; それぞれの実装のドキュメントを参照してください。

参考

並行処理とマルチスレッド処理

### 使用例

サブプロセスの制御のために `Process` クラスを使い、サブプロセスの標準出力を読み出すために `StreamReader` を使う例です。

サブプロセスは `create_subprocess_exec()` 関数により生成されます:

    import asyncio
    import sys

    async def get_date():
        code = 'import datetime as dt; print(dt.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 を使って書かれた 同様の例 も参照してください。