私は、コンカレントプログラミングの「何も共有しない」という原則の下で取り組んできました。基本的に、すべてのワーカースレッドには、同じ状態の不変の読み取り専用コピーがあり、それらの間で共有されることはありません(参照によっても)。一般的に言って、これは本当にうまくいきました。
現在、誰かがすべてのスレッドが同時にアクセスしているロックなしのシングルトンキャッシュ(たとえば、静的辞書)を導入しています。起動後に辞書が変更されることはないため、ロックはありません。スレッドセーフの問題は発生していませんが、パフォーマンスが低下しています。
問題は...ロックがないため、このシングルトンの導入によってパフォーマンスに影響が出るのはなぜですか。これを説明できるカバーの下で正確に何が起こっているのですか?
確認すると、この新しいシングルトンへのアクセスが唯一の変更であり、キャッシュへの呼び出しをコメント化するだけで確実に再作成できます。
不変の状態は、変更可能なものとキャッシュラインを共有している可能性があります。この場合、近くの変更可能な状態mightに変更すると、コア全体でこのキャッシュラインの再同期が強制されるため、パフォーマンスが低下する可能性があります。
ディクショナリのキーとして使用するオブジェクトのEquals()
およびGetHashCode()
メソッドに、スレッドに対応していない予期しない副作用がないことを確認します。プロファイリングは、ここで大いに役立ちます。
万が一キーが文字列である場合、おそらくそこにあります:噂によると、文字列は不変オブジェクトのように動作しますが、特定の最適化のために、内部的にはマルチスレッド化に伴うすべての変更可能な方法で実装されています。
辞書をシングルトンの代わりに通常の参照として使用するスレッドに辞書を渡して、問題が辞書の共有性と単一性のどちらにあるかを確認します。 (考えられる原因の除去。)
また、その使用によって驚くべき結果が得られる場合に備えて、通常のConcurrentDictionary
ではなくDictionary
を試してみます。 ConcurrentDictionary
のパフォーマンスが通常のDictionary
よりもはるかに優れている、またははるかに悪いことが判明した場合、当面の問題について推測すべきことがたくさんあります。
上記のいずれも問題を指摘していない場合、ガベージコレクターがかどうかを把握しようとしているため、パフォーマンスの低下はガベージコレクションスレッドと残りのスレッドとの間の奇妙な種類の競合が原因であると思いますディクショナリ内のオブジェクトは、スレッドによってアクセスされている間、破棄する必要があります。