ProcessPoolExecutor と ThreadPoolExecutor の違いは何ですか? 質問する

ProcessPoolExecutor と ThreadPoolExecutor の違いは何ですか? 質問する

基本的な理解を得るためにドキュメントを読みましたが、 をProcessPoolExecutor回避できるということしか示されていませんでした。これは、並列プロセスが同時に値を更新しないように変数または関数をGlobal Interpreter Lockロックする方法だと思います。

私が知りたいのは、それぞれのアプローチをいつProcessPoolExecutor、いつ使用するかThreadPoolExecutor、また使用する際に何を念頭に置くべきかということです。

ベストアンサー1

ProcessPoolExecutor各ワーカーを独自の子プロセスで実行します。

ThreadPoolExecutorメインプロセス内の個別のスレッドで各ワーカーを実行します。

グローバル インタープリタ ロック (GIL) は、変数や関数をロックするだけでなく、インタープリタ全体をロックします。つまり、 などの組み込み操作はすべて、listodicts[3]['spam'] = eggs自動的にスレッドセーフになります。

しかし、これはまた、コードが CPU 依存 (つまり、ネットワーク応答の待機などではなく計算に時間を費やす) であり、GIL を解放するように設計された外部ライブラリ (NumPy など) でほとんどの時間を費やしていない場合は、一度に 1 つのスレッドのみが GIL を所有できることも意味します。したがって、4 つのスレッドがある場合、コアが 4 つまたは 16 個ある場合でも、ほとんどの場合、そのうち 3 つは GIL を待機していることになります。そのため、4 倍高速になる代わりに、コードは若干遅くなります。

繰り返しになりますが、I/O バウンド コード (たとえば、多数の HTTP リクエストに対する多数のサーバーの応答を待機する) の場合、スレッドは問題ありません。これが問題になるのは、CPU バウンド コードのときだけです。

それぞれの子プロセスには独自の GIL があるため、この問題は発生しません。コードが CPU に依存している場合でも、4 つの子プロセスを使用すると、ほぼ 4 倍の速度で実行できます。

しかし、子プロセスは変数を共有しません。通常、これは良いことです。関数への引数として値(のコピー)を渡し、値(のコピー)を返すので、プロセスの分離により、これが安全に行われていることが保証されます。しかし、場合によっては(通常はパフォーマンス上の理由ですが、 経由でコピーできないオブジェクトを渡すためpickle)、これは受け入れられないため、スレッドを使用するか、モジュール内のより複雑な明示的な共有データ ラッパーを使用する必要がありますmultiprocessing

おすすめ記事