# 18.5.6. サブプロセス

ソースコード: Lib/asyncio/subprocess.py

## 18.5.6.1. Windows でのイベントループ

Windows では、デフォルトのイベントループは `SelectorEventLoop` になりますが、これはサブプロセスをサポートしていません。代わりに `ProactorEventLoop` を使用します。Windows で使用する例:

    import asyncio, sys

    if sys.platform == 'win32':
        loop = asyncio.ProactorEventLoop()
        asyncio.set_event_loop(loop)

参考

利用可能なイベントループ および プラットフォームでのサポート。

## 18.5.6.2. サブプロセスの作成: Process を使用した高水準 API

coroutine `asyncio.``create_subprocess_exec`(*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)

  サブプロセスを作成します。

  limit 引数で `StreamReader` に渡すバッファリミットを設定します。他の引数については `AbstractEventLoop.subprocess_exec()` を参照してください。

  `Process` のインスタンスを返します。

  この関数は コルーチン です。

coroutine `asyncio.``create_subprocess_shell`(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, **kwds)

  シェルコマンド cmd を実行します。

  limit 引数で `StreamReader` に渡すバッファリミットを設定します。他の引数については `AbstractEventLoop.subprocess_shell()` を参照してください。

  `Process` のインスタンスを返します。

  シェルインジェクション の脆弱性を回避するために、すべての空白文字およびメタ文字を適切にクオートすることはアプリケーション側の責任です。 `shlex.quote()` 関数は、シェルコマンドで使用される文字列内の、空白文字とシェルのメタ文字の適切なエスケープに使用できます。

  この関数は コルーチン です。

パイプに接続するには `AbstractEventLoop.connect_read_pipe()` および `AbstractEventLoop.connect_write_pipe()` メソッドを使用します。

## 18.5.6.3. サブプロセスの作成: subprocess.Popen を使用した低水準 API

`subprocess` モジュールを使用して非同期にサブプロセスを実行します。

coroutine `AbstractEventLoop.``subprocess_exec`(protocol_factory, *args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)

  1 個以上の文字列引数 (ファイルシステムエンコーディング にエンコードされた文字列またはバイト列) からサブプロセスを作成します。先頭の文字列で実行するプログラムを指定し、残りの文字列でプログラムの引数を指定します (それが Python スクリプトであれば、`sys.argv` の値に相当します)。これは標準ライブラリの `subprocess.Popen` クラスが shell=False で呼び出され、文字列のリストが第 1 引数として渡されたときと似ていますが、`Popen` が引数として文字列のリストを 1 個取るのに対し、`subprocess_exec()` 引数として複数の文字列を取ります。

  protocol_factory はクラス `asyncio.SubprocessProtocol` のサブクラスを作成しなくてはなりません。

  その他の引数:

  - stdin: `connect_write_pipe()` を使用してサブプロセスの標準入力ストリームに接続されたパイプを表すファイルライクオブジェクト、もしくは定数 `subprocess.PIPE` (デフォルト) のどちらかになります。 デフォルトでは、パイプが新しく作成され、接続されます。

  - stdout: `connect_read_pipe()`, を使用してサブプロセスの標準出力ストリームに接続されたパイプを表すファイルライクオブジェクト、もしくは定数 `subprocess.PIPE` (デフォルト) のどちらかになります。 デフォルトでは、パイプが新しく作成され、接続されます。

  - stderr: `connect_read_pipe()` を使用してサブプロセスの標準エラー出力ストリームに接続されたパイプを表すファイルライクオブジェクト、もしくは定数 `subprocess.PIPE` (デフォルト) と定数 `subprocess.STDOUT` のどちらかになります。 デフォルトでは、パイプが新しく作成され、接続されます。 `subprocess.STDOUT` が指定された場合、サブプロセスの標準エラー出力ストリームは標準出力ストリームと同じパイプに接続されます。

  - その他のキーワード引数は、指定してはならない bufsize、universal_newlines および shell を除き、すべて解釈されずに `subprocess.Popen` に渡されます。

  `(transport, protocol)` のペアを返します。transport は `BaseSubprocessTransport` のインスタンスです。

  このメソッドは コルーチン です。

  引数については `subprocess.Popen` クラスのコンストラクタを参照してください。

coroutine `AbstractEventLoop.``subprocess_shell`(protocol_factory, cmd, *, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)

  プラットフォームの "シェル" 構文を使用して cmd (ファイルシステムエンコーディング にエンコードされた文字列またはバイト列) からサブプロセスを作成します。これは標準ライブラリ `subprocess.Popen` クラスを `shell=True` で呼び出したときと似ています。

  protocol_factory はクラス `asyncio.SubprocessProtocol` のサブクラスを作成しなくてはなりません。

  その他の引数についての詳細は `subprocess_exec()` を参照してください。

  `(transport, protocol)` のペアを返します。transport は `BaseSubprocessTransport` のインスタンスです。

  シェルインジェクション の脆弱性を回避するために、すべての空白文字およびメタ文字を適切にクオートすることはアプリケーション側の責任です。 `shlex.quote()` 関数は、シェルコマンドで使用される文字列内の、空白文字とシェルのメタ文字の適切なエスケープに使用できます。

  このメソッドは コルーチン です。

参考

`AbstractEventLoop.connect_read_pipe()` および `AbstractEventLoop.connect_write_pipe()` メソッド。

## 18.5.6.4. 定数

`asyncio.subprocess.``PIPE`

  `create_subprocess_shell()` および `create_subprocess_exec()` の引数 stdin、stdout あるいは stderr で使用できる特殊な値です。オープンすべき標準ストリームへのパイプを示します。

`asyncio.subprocess.``STDOUT`

  `create_subprocess_shell()` および `create_subprocess_exec()` の引数 stderr で使用できる特殊な値です。標準エラー出力を標準出力と同様に扱うための標準出力へのパイプを示します。

`asyncio.subprocess.``DEVNULL`

  `create_subprocess_shell()` および `create_subprocess_exec()` の引数 stdin、stdout あるいは stderr で使用できる特殊な値です。特殊ファイル `os.devnull` を使用するよう示します。

## 18.5.6.5. Process

class `asyncio.subprocess.``Process`

  関数 `create_subprocess_exec()` あるいは `create_subprocess_shell()` によって作成されたサブプロセスです。

  `Process` クラスの API は `subprocess.Popen` クラスの API に似せて設計されましたが、一部異なります:

  - 明示的な `poll()` メソッドはありません

  - `communicate()` および `wait()` メソッドは timeout 引数を取りません: `wait_for()` 関数を使用してください

  - universal_newlines 引数はサポートされません (バイト文字列のみサポートします)

  - `Process` クラスの `wait()` メソッドは非同期であるのに対し、`Popen` クラスの `wait()` メソッドはビジーループとして実装されています。

  このクラスは スレッド安全ではありません。 asyncio-subprocess-threads 節を参照してください。

  coroutine `wait`()

    プロセスの終了を待ちます。リターンコードが `returncode` 属性に設定され、返されます。

    このメソッドは コルーチン です。

    注釈

    `stdout=PIPE` または `stderr=PIPE` を使用しており、OS パイプバッファのそれ以上のデータを受け取りの待機をブロックするほど子プロセスがパイプに出力した場合、このメソッドはデッドロックします。 これを回避するには `communicate()` メソッドを使用してください。

  coroutine `communicate`(input=None)

    プロセスと交信、すなわち、標準入力へのデータ送信、EOF に達するまで標準出力および標準エラー出力からのデータ受信、およびプロセスの終了の待機を行います。任意の引数 input は子プロセスに送信するデータを設定します。送信するデータがない場合は `None` を設定します (デフォルト)。input はバイト列でなければなりません。

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

    input を標準入力に書き込んだときに `BrokenPipeError` または `ConnectionResetError` 例外が送出された場合、例外は無視されます。これは全データが標準入力に書き込まれる前にプロセスが終了したときに発生します。

    プロセスの標準入力にデータを送りたい場合、`stdin=PIPE` で Process オブジェクトを作成する必要があります。同様に、結果のタプルに `None` 以外のものを受け取りたい場合には `stdout=PIPE` および/または `stderr=PIPE` を指定する必要があります。

    このメソッドは コルーチン です。

    注釈

    受信したデータはメモリにバッファーされます。そのため、返されるデータが大きいかあるいは制限がないような場合はこのメソッドを使うべきではありません。

    バージョン 3.4.2 で変更: このメソッドは `BrokenPipeError` および `ConnectionResetError` を無視するようになりました。

  `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 では `kill()` は `terminate()` の別名になります。

  `stdin`

    標準入力ストリーム (`StreamWriter`) になります。プロセスが `stdin=None` で作成されていた場合 `None` になります。

  `stdout`

    標準出力ストリーム (`StreamReader`) になります。プロセスが `stdout=None` で作成されていた場合 `None` になります。

  `stderr`

    標準エラー出力ストリーム (`StreamReader`) になります。プロセスが `stderr=None` で作成されていた場合 `None` になります。

  警告

  ストリームの読み込みまたは書き込みの一時停止およびプロセスのブロックによるデッドロックを回避するには、`.stdin.write`、`.stdout.read` あるいは `.stderr.read` ではなく、`communicate()` メソッドを使用してください。

  `pid`

    プロセスの識別子です。

    `create_subprocess_shell()` 関数によって作成されたプロセスでは、この属性は生成したシェルのプロセス識別子になる点に注意してください。

  `returncode`

    プロセスが終了したときのリターンコードです。`None` 値はプロセスがまだ終了していないことを示します。

    負の値 `-N` は子プロセスがシグナル `N` により中止させられたことを示します (Unix のみ)。

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

asyncio はサブプロセスを異なるスレッドから実行するのをサポートしていますが、制限があります:

- イベントループはメインスレッド内で実行されなければなりません

- 子ウォッチャーは、他のスレッドからサブプロセスが実行される前に、メインスレッドで作成されなければなりません。 メインスレッドで `get_child_watcher()` を呼んで子ウォッチャーをインスタンス化してください。

`asyncio.subprocess.Process` クラスはスレッド安全ではありません。

参考

asyncio-multithreading

## 18.5.6.7. サブプロセスの例

### 18.5.6.7.1. トランスポートおよびプロトコルを使用したサブプロセス

サブプロセスの出力を取得しサブプロセスの終了を待機するサブプロセスプロトコルの例です。サブプロセスは `AbstractEventLoop.subprocess_exec()` メソッドで作成されます:

    import asyncio
    import sys

    class DateProtocol(asyncio.SubprocessProtocol):
        def __init__(self, exit_future):
            self.exit_future = exit_future
            self.output = bytearray()

        def pipe_data_received(self, fd, data):
            self.output.extend(data)

        def process_exited(self):
            self.exit_future.set_result(True)

    @asyncio.coroutine
    def get_date(loop):
        code = 'import datetime; print(datetime.datetime.now())'
        exit_future = asyncio.Future(loop=loop)

        # Create the subprocess controlled by the protocol DateProtocol,
        # redirect the standard output into a pipe
        create = loop.subprocess_exec(lambda: DateProtocol(exit_future),
                                      sys.executable, '-c', code,
                                      stdin=None, stderr=None)
        transport, protocol = yield from create

        # Wait for the subprocess exit using the process_exited() method
        # of the protocol
        yield from exit_future

        # Close the stdout pipe
        transport.close()

        # Read the output which was collected by the pipe_data_received()
        # method of the protocol
        data = bytes(protocol.output)
        return data.decode('ascii').rstrip()

    if sys.platform == "win32":
        loop = asyncio.ProactorEventLoop()
        asyncio.set_event_loop(loop)
    else:
        loop = asyncio.get_event_loop()

    date = loop.run_until_complete(get_date(loop))
    print("Current date: %s" % date)
    loop.close()

### 18.5.6.7.2. ストリームを使用したサブプロセス

サブプロセスを制御する `Process` クラスと標準出力から読み込む `StreamReader` クラスを使用した例で得す。サブプロセスは `create_subprocess_exec()` 関数で作成されます:

    import asyncio.subprocess
    import sys

    @asyncio.coroutine
    def get_date():
        code = 'import datetime; print(datetime.datetime.now())'

        # Create the subprocess, redirect the standard output into a pipe
        create = asyncio.create_subprocess_exec(sys.executable, '-c', code,
                                                stdout=asyncio.subprocess.PIPE)
        proc = yield from create

        # Read one line of output
        data = yield from proc.stdout.readline()
        line = data.decode('ascii').rstrip()

        # Wait for the subprocess exit
        yield from proc.wait()
        return line

    if sys.platform == "win32":
        loop = asyncio.ProactorEventLoop()
        asyncio.set_event_loop(loop)
    else:
        loop = asyncio.get_event_loop()

    date = loop.run_until_complete(get_date())
    print("Current date: %s" % date)
    loop.close()