Python製の非同期ジョブフレームワークであるCeleryのワーカープロセスには 4種類のプールがある。それぞれに挙動の違いと長短がある。
プール
prefork
標準ライブラリのmultiprocessingをベースに実装されている。タスクの処理を行うプロセスを子プロセスとしてforkする。別のプロセスとして動作するため、GILの制約を受けない。CPUバウンドの処理を複数のワーカーで行う場合、パフォーマンス的に有利になる事がある。親プロセスがSIGTERMを受け取った場合、親プロセスは子プロセスで実行中のタスクが完了した後に終了する。
prefork: celery -A main.app worker --pool prefork --concurrency 1
eventlet
サードパーティライブラリのeventletをベースに実装されている。タスクの処理をeventletベースのGreenletプールによって実行する。同一プロセス内での実行のため、GILの制約を受ける。IOバウンドの処理を複数のワーカーで行う場合、パフォーマンス的に有利になる事がある。SIGTERMを受け取った場合、プロセスは実行中のタスクの完了後に終了する。
eventlet: EVENTLET_HUB=poll celery -A main.app worker --pool eventlet --concurrency 1
macOS 11.2.3, Python3.9, eventlet-0.30.2で動作を行ったところ=EVENTLET_HUB=poll= の設定を行わないと起動時にエラーが発生した。
gevent
サードパーティライブラリのgeventをベースに実装されている。タスクの処理をgeventベースのGreenletプールによって実行する。同一プロセス内での実行のためGILの制約を受ける。IOバウンドの処理を複数のワーカーで行う場合、パフォーマンス的に有利になる事がある。SIGTERMを受け取った場合、プロセスは実行中のタスクの完了後に終了する。
gevent: celery -A main.app worker --pool gevent --concurrency 1
solo
ワーカープロセスが直接タスクを処理する。メインループでタスクを処理しコンテキストスイッチがないため、CPUバウンドでの処理にパフォーマンスを発揮する事がある。子プロセスやスレッドのような機構を使わないため、ワーカープロセス数はワーカー数と同じになる。そのため管理がシンプルになり、マイクロサービスなどの複雑な環境下では扱いやすい。SIGTERMを受け取った場合、実行中のタスクの完了を待たず即座に終了する。
celery -A main.app worker --pool solo
シグナル
ワーカープロセスにシグナルを送ることで、終了の仕方やダンプなどの挙動を指示できる。
シグナル | 挙動 |
---|---|
TERM | タスクの完了を待ってシャットダウンする。 |
QUIT | 即座にシャットダウンする。 |
USR1 | ダンプを出力する。 |
USR2 | リモートデバッグの待受を開始する。 |