LoginSignup
1
2

More than 3 years have passed since last update.

Pythonでプロセスについて勉強してみた

Posted at

概要

  • pythonを使ってプロセスの生成周りを学習し直したメモ
  • subprocessモジュールなどもあるが、自分で実装して勉強し直したメモ
  • 備忘録

前提

  • 環境
    • python: v.3.7.7

基礎

  • os.fork()
    • fork により、そのプロセスのコピーができる。
    • 複製された方が「子」、作った方は「親」
    • 子プロセスでは 0 が返り、親プロセスでは子プロセスの id が返る
    • forkしたプロセスは、親プロセスが処理終了を待つことはない
      • 親プロセスが先に終了すると、子プロセスでos._exit()してもゾンビプロセスとして残ってしまうので注意
    • つまり
      • forkすると、その時点で処理が分岐される
      • 親は子の終了は待たない
      • 分岐した際に、自分が子or親の判定は、fork()の返り値が0 or !0で判定する
      • 定石としては、親プロセス側の処理として子プロセスの処理を待つ(waitpidなど)で待つか放置して待つのか、killするのかを書く
      • 放置した場合は、子プロセスが終了してもゾンビとして残る可能性がある
  • os._exit()
    • fork()によって作られた子プロセスを終了させる
  • os.exec()
    • 外部コマンドを実行する
    • execの引数は以下例の組合せで変わる
      • v : tuple もしくは list で実行するプログラムの引数を指定する
        • 例) execvp('python', ['python', 'test.py'])
      • l は文字列を指定する
        • 例) execlp('python', 'python', 'test.py')
      • p : 実行するプログラムをシステムパス (ie. PATH) から探す
      • e : 実行時に指定する環境変数の Dictionary を最後の引数で指定できる。指定するとこの関数を呼んだプログラムが持っていた環境変数(=PCにデフォルトで設定されている環境変数)は引き継がれないので、追加する場合は os.environ で取得した環境変数に追加したものを渡す
  • os.waitpid(sid, option)
    • option=0で指定したプロセスIDの処理が終わるまで待つ
      • これをかまさないと、子プロセスでos._exec()してもプロセスがゾンビとして残り続ける。つまり、子プロセスが終了しようとしたとき、親プロセスがwaitしてないと、そのプロセスはゾンビ状態となって残る
    • option=os.WNOHANGとすると、子プロセスの状態を判定する。この時、呼び出し元のプロセスは、ブロッキングされない(=待ち合わせない)ため、子プロセスの終了を待ち続けない
    • os.setid()
      • プロセスグループのリーダとなる = 制御端末を持つ
      • 制御端末を持つまでの流れ
        1. 新しいセッションを作成する。
        2. 呼び出したプロセスを新しいセッションのリーダーにする。
        3. プロセスを制御端末から切り離す。
  • memo:
    • 子プロセスが先に _exit したあと、親がwaitpidするとどうなるのか?子供は先にkillされてゾンビにならないのか?
      • きちんとwaitpidをすることで子プロセスがkillされた。逆に、子が先に処理が終わったからといってwaitpidしないとゾンビになるので注意。

応用

  • djangoにおいて、リクエストを返した後も長時間ジョブとしてプロセスで処理を回したい場合の実装例
    • double fork
      • 実験
        • 1回forkしてrunscript -> 親はwaitせずにreturn → 当然子プロセスはゾンビ化
        • 2回forkすると孫プロセスはinit配下の子プロセスとなる → 孫プロセスが終了する → ゾンビ化せずに消える
      • キモはsetsid()が効いていることで、孫プロセスがデーモン化した
        1. 子プロセスはfork後、セッションリーダーとなり、制御端末を親プロセスとは別にもつ
        2. 子プロセスは孫プロセスをfork
        3. 子プロセスは即時exit()して親プロセスはwaitpidで待ち合わせる→子プロセスのkillとゾンビ化を防ぐ
        4. 孫プロセスはセッションリーダーでないことが自明なのでデーモンとして制御端末を持たないことが約束される
        5. 孫プロセスは子プロセスが終了するとinitプロセス(root)配下においてプロセスの後処理をしてくれるので、処理終了後ゾンビにならない
  • セッションとプロセスについて
    • すべてのプロセスは、セッションに属するグループに属し、階層が存在する。
    • セッション(SID)→プロセスグループ(PGID)→プロセス(PID)
      • プロセスグループ内の最初のプロセスがプロセスグループリーダーになる
      • セッション内の最初のプロセスがセッションリーダーになる
    • すべてのセッションに1つのTTYを関連付け、セッションリーダーのみがTTYを制御できる。
    • プロセスがデーモン化される(バックグラウンドで実行される)ためには、セッションリーダがkill されてセッションがTTYを制御する可能性がないようにする必要がある

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2