各サブプロセスが何もしない単純な例を試してみると、この動作が見られないため、モジュールtime.sleep()
に固有のものではないと思います。multiprocessing
私の最善の推測は、内部で使用されている可能性が高いfork()
のメモリ複製機能です。multiprocessing
Unix で新しいプロセスをフォークするセマンティクスでは、親プロセスのメモリ空間全体を子プロセスに複製する必要があります。MySubProcess
したがって、これらの構造のいずれかを開始する前に、これらの構造のリストを作成しているとしましょう。このリストは、各子プロセスのアドレス空間に複製されるため、これらの各プロセスの常駐サイズを見ると、かなり大きくなります (構造がかなりの量のメモリを占有すると仮定します)。
また、子プロセスを起動する前に割り当てる他のメモリは複製されますが、インスタンスのリストは、より多くのプロセスを割り当てるとサイズが大きくなると私が考えることができる主なものでした. コードによっては、プロセスの数に応じてスケーリングする他のデータ構造が存在する場合があります (ワーク キューなど)。
del
各子のコンテキストで必要のないものすべてを使用すると、サイズが元に戻る可能性がありますが、これは Python アロケーターとシステム メモリ アロケーターの間の非常に複雑な相互作用に依存しているため、確実ではありません。基本的に、Python は再利用のために解放されたメモリを保持することができ、Python インタープリターがそうしなくても、システム アロケーターはそうする可能性があります。要するに、これはおそらく努力する価値がありません-詳細については、私の回答の最後を参照してください。
ただし、Linux (およびその他の最新の Unix バリアント) は、いわゆるコピー オン ライトセマンティクスを使用して、 の動作がfork()
それほど非効率的ではないことを確認しているため、これは見かけほど悪くはありません。基本的に、子プロセスは親プロセスと同じメモリ ページへの参照を保持します。どちらのプロセスも何も変更しない限り、メモリは実際には複製されませんが、両方のプロセスのメモリ使用量を合計すると、プロセスごとのアプローチは、ページの共有に気付くほどスマートではないため、2 回カウントされました。これは、同じ基になるファイルへの複数のハード リンクを持つことと似ています。ps
top
プロセスがメモリ ページに書き込むと、それがコピーされ (「コピー オン ライト」という名前が付けられます)、実際の物理メモリが使用されます。この場合、必要な追加メモリの量を予測するのは非常に困難です。これは、Python データ構造を物理メモリ ページまでマッピングする必要があるためです。ただし、原則そのものが重要です。
free
ユーティリティを使用してシステム全体のメモリ使用量を表示し、2 つのケースの数値を比較することで、私の理論が正しいかどうかをテストできます。正しければ、100 サブプロセスのケースでメモリがいくらか増加していることがわかりますが、それほど多くはありません。各プロセスのメモリ使用量を調べると示唆されるように。2 行目 (つまり行) の数値を使用することを忘れないでください-/+ buffers/cache
。これにより、2 つのテスト間のファイルシステム キャッシュの変更がスムーズになります。
これが正しいと仮定すると、親プロセスが多くのメモリを割り当てる前に、子プロセスをできるだけ早く開始することをお勧めします。ただし、これに最善を尽くす以外は、おそらくあまり心配する必要はありません。ページが書き込み時にコピーされたとしても、子プロセスによってアクセスされないため、次のようにディスクにスワップアウトされます。必要であり、スワップインされない可能性が高いため、パフォーマンスに大きな影響を与えることはありません (プラットフォームにスワップがない場合を除く)。
最後に 1 つ - 実際には、マシン上のコアよりも多くのワーカー プロセスを作成してもほとんど意味がありません。これは、非常に特殊なハードウェアを使用していない限り、通常は約 8 または 16 を超えません。あまりにも多くのプロセスを作成すると、利益を得るよりもすべてのプロセスをスケジューリングするのに多くの時間を浪費している可能性があります.何をしても、物理コア以上の並列化は得られません (ただし、ハイパースレッディングはこれを少し複雑にします)。
This other SO questionは、より有用な情報を提供する可能性があります。