サブプロセス
************

**ソースコード:** 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()" 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* を送信します。

      注釈:

        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 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 を使って書かれた 同様の例 も参照してください。
