web-dev-qa-db-ja.com

IPC共有メモリとスレッドメモリのパフォーマンスの違い

プロセス間で共有メモリセグメントにアクセスしても、スレッド間でプロセスメモリにアクセスする場合に比べてパフォーマンスが低下しないとよく耳にします。言い換えると、マルチスレッドアプリケーションは、共有メモリを使用する一連のプロセスよりも高速ではありません(ロックやその他の同期の問題を除く)。

しかし、私には疑問があります。

1)shmat()は、ローカルプロセスの仮想メモリを共有セグメントにマップします。この変換は、共有メモリアドレスごとに実行する必要があり、かなりのコストがかかる可能性があります。マルチスレッドアプリケーションでは、追加の変換は必要ありません。共有メモリにアクセスしない通常のプロセスと同様に、すべてのVMアドレスが物理アドレスに変換されます。

2)共有メモリセグメントはカーネルによって維持されなければなりませんどういうわけか。たとえば、shmに接続されているすべてのプロセスが削除されても、shmセグメントはまだ稼働しており、最終的には新しく開始されたプロセスから再度アクセスできます。 shmセグメントでのカーネル操作に関連するオーバーヘッドが発生する可能性があります。

マルチプロセス共有メモリシステムは、マルチスレッドアプリケーションと同じくらい高速ですか?

20
Robert Kubrick

1)shmat()は、ローカルプロセスの仮想メモリを共有セグメントにマップします。この変換は、共有メモリアドレスごとに実行する必要があり、shmアクセスの数に比べてかなりのコストがかかる可能性があります。マルチスレッドアプリケーションでは、追加の変換は必要ありません。共有メモリにアクセスしない通常のプロセスと同様に、すべてのVMアドレスは物理アドレスに変換されます。

1ページ(4または8)のLinuxのほとんどのフレーバーでは、共有ページをセットアップするための初期コスト(shmat()を呼び出すプロセスでページテーブルにデータを入力する)を除いて、通常のメモリアクセスと比較してオーバーヘッドはありません。バイト)共有メモリの4KBあたり。

ページが共有に割り当てられているか、同じプロセス内に割り当てられているかにかかわらず、(関連するすべての比較に対して)同じコストです。

2)共有メモリセグメントは、カーネルによって何らかの方法で維持される必要があります。パフォーマンスの観点から「どういうわけか」が何を意味するのかわかりませんが、たとえば、shmに接続されているすべてのプロセスが削除されても、shmセグメントはまだ稼働しており、最終的には新しく開始されたプロセスから再度アクセスできます。 shmセグメントの存続期間中にカーネルがチェックする必要があるものに関連して、少なくともある程度のオーバーヘッドが必要です。

共有されているかどうかに関係なく、メモリの各ページには「構造体ページ」が添付されており、ページに関するデータが含まれています。項目の1つは参照カウントです。ページがプロセスに渡されると(「shmat」またはその他のメカニズムを介して)、参照カウントが増加します。何らかの方法で解放されると、参照カウントが減少します。デクリメントされたカウントがゼロの場合、ページは実際に解放されます。それ以外の場合、「それ以上何も起こりません」。

割り当てられた他のメモリと比較して、オーバーヘッドは基本的にゼロです。同じメカニズムがとにかくページの他の目的に使用されます-たとえば、カーネルによっても使用されるページがある場合-プロセスが終了すると、カーネルは、カーネルによってリリースされるまでそのページを解放しないことを知る必要があります。同様にユーザープロセス。

「フォーク」が作成されたときにも同じことが起こります。プロセスがフォークされると、親プロセスのページテーブル全体が基本的に子プロセスにコピーされ、すべてのページが読み取り専用になります。書き込みが発生するたびに、カーネルによって障害が発生し、そのページがコピーされます。そのため、そのページのコピーが2つあり、書き込みを行うプロセスは、他のプロセスに影響を与えることなく、そのページを変更できます。子(または親)プロセスが終了すると、もちろん、両方のプロセスがまだ所有しているすべてのページ[書き込まれることのないコードスペースや、おそらく触れられない共通データの束など]は明らかにできません。両方のプロセスが「デッド」になるまで解放されます。ここでも、参照カウントされたページが役立ちます。これは、各ページの参照カウントのみをカウントダウンし、参照カウントがゼロの場合、つまり、そのページを使用するすべてのプロセスがそれを解放した場合、そのページは実際には「便利なページ」として戻ってきました。

共有ライブラリでもまったく同じことが起こります。 1つのプロセスが共有ライブラリを使用している場合、そのプロセスが終了すると解放されます。ただし、2つ、3つ、または100のプロセスが同じ共有ライブラリを使用する場合、ページが不要になるまでコードをメモリに保持する必要があります。

したがって、基本的に、カーネル全体のすべてのページはすでに参照カウントされています。オーバーヘッドはほとんどありません。

11
Mats Petersson

2つのスレッドまたはプロセスが同じメモリにアクセスしているときにマイクロエレクトロニクスレベルで何が起こっているかを考えると、いくつかの興味深い結果があります。

興味深いのは、CPUのアーキテクチャにより、複数のコア(つまりスレッドとプロセス)が同じメモリにアクセスできるようにする方法です。これは、L1キャッシュ、次にL2、L3、最後にDRAMを介して行われます。そのすべてのコントローラー間で調整を行う必要があります。

CPUが2つ以上あるマシンの場合、その調整はシリアルバスを介して行われます。 2つのコアが同じメモリにアクセスしているときに発生するバストラフィックを比較し、データがコピー別のメモリにある場合、それはほぼ同じ量のトラフィックです。

したがって、マシンのどこで2つのスレッドが実行されているかに応じて、データをコピーする場合と共有する場合の速度の低下はほとんどありません。

コピーは、1)memcpy、2)パイプ書き込み、3)内部DMA転送(Intelチップは最近これを行うことができます)です。

内部DMAはCPU時間を必要としないので興味深いです(ナイーブなmemcpyは単なるループであり、実際には時間がかかります)。したがって、データを共有する代わりにデータをコピーでき、これを内部DMAを使用すると、データを共有しているかのように高速にできます。

ペナルティはRAMの増加ですが、その見返りは、アクターモデルプログラミングのようなものが機能していることです。これは、プログラムからセマフォを使用して共有メモリを保護する複雑さをすべて取り除く方法です。

4
bazza

共有メモリの設定にはカーネルによる追加の作業が必要になるため、プロセスからの共有メモリ領域のアタッチ/デタッチは、通常のメモリ割り当てよりも遅くなる可能性があります(または、ベンチマークを行ったことがない場合もあります)。ただし、プロセスの仮想メモリマップにアタッチされると、共有メモリは、同じキャッシュラインサイズのチャンクを競合する複数のプロセッサがある場合を除いて、アクセス用の他のメモリと同じです。したがって、一般に、共有メモリはほとんどのアクセスで他のメモリと同じくらい高速である必要がありますが、そこに何を置くか、およびそれにアクセスするさまざまなスレッド/プロセスの数によっては、特定の使用パターンで速度が低下する可能性があります。

3
twalberg

共有メモリのアタッチ( shmat )とデタッチ(shmdt)のコストに加えて、アクセスも同様に高速である必要があります。言い換えれば、ハードウェアがサポートしているので高速である必要があります。アクセスごとに追加のレイヤーの形でオーバーヘッドがあってはなりません。

同期も同様に高速である必要があります。たとえば、Linuxでは futex をプロセスとスレッドの両方に使用できます。原子変数も正常に機能するはずです。

取り付け/取り外しのコストが支配的でない限り、プロセスを使用することに不利な点はありません。ただし、スレッドは単純であり、プロセスの寿命がほとんどない場合は、オーバーヘッドのアタッチ/デタッチが問題になる可能性があります。ただし、プロセスを作成するためのコストは高くなるため、パフォーマンスが心配な場合は、これはありそうなシナリオではありません。

最後に、この議論は興味深いかもしれません: shmatとshmdtは高価ですか? 。 (警告:かなり時代遅れです。それ以来状況が変わったかどうかはわかりません。)

この関連する質問も役立つ可能性があります: IPCの共有メモリとスレッドの共有メモリの違いは何ですか? (簡単な答え:あまりありません。)

2
Philipp Claßen

共有メモリのコストは、共有メモリへの「メタ」変更の数に比例します:割り当て、割り当て解除、プロセス終了、...

メモリアクセスの数は影響しません。共有セグメントへのアクセスは、他の場所へのアクセスと同じくらい高速です。

CPUはページテーブルマッピングを実行します。物理的には、CPUはマッピングが共有されていることを認識していません。

ベストプラクティス(マッピングを変更することはめったにありません)に従うと、基本的にプロセスプライベートメモリの場合と同じパフォーマンスが得られます。

2
usr