低レベルのロックを取り除くテクニック
-
02-07-2019 - |
質問
私は低レベルのロックを減らすために適用できる戦略を考えており、それを必要としています。ただし、ここでの注意点は、これはサーバー アプリケーション用の新しいコード (数万行の C++ コード) ではないため、すべてを書き直すことはできないということです。
この問題に対する解決策は今ではないのではないかと心配しています(手遅れです)。ただし、他の人が使用した良いパターンについて聞きたいです。
現時点ではロックが多すぎますが、競合はそれほど多くないため、これはパラノイアによって引き起こされたハードウェア パフォーマンスの問題です。このコードを説明するのに最も適切な方法は、シングル スレッドのコードに突然ロックが散りばめられているということです。
解決
なぜ低レベルのロックを排除する必要があるのでしょうか?デッドロックの問題はありますか?パフォーマンスに問題がありますか?それともスケーリングの問題でしょうか?ロックは一般に競合するものですか、それとも競合しないものですか?
どのような環境を使用していますか?C++ での答えは、たとえば Java での答えとは異なります。例えば。Java 6 の競合のない同期ブロックは、実際にはパフォーマンスの点で比較的安価であるため、JRE をアップグレードするだけで、解決しようとしている問題を解決できる可能性があります。別のコンパイラまたはロック ライブラリに切り替えることで、C++ でも同様のパフォーマンス向上が得られる可能性があります。
一般に、取得するミューテックスの数を減らすための戦略がいくつかあります。
まず、単一のスレッドからのみアクセスされるものにはミューテックスは必要ありません。
第二に、不変のものはすべて、「安全に公開」されていれば安全です(つまり、部分的に構築されたオブジェクトが別のスレッドに決して表示されないような方法で作成されます)。
第三に、ほとんどのプラットフォームはアトミック書き込みをサポートするようになりました。これは、単一のプリミティブ型 (ポインターを含む) だけを保護する必要がある場合に役立ちます。これらは、データベースのオプティミスティック ロックと非常によく似た働きをします。また、アトミック書き込みを使用してロックフリー アルゴリズムを作成し、Map 実装などのより複雑な型を置き換えることもできます。ただし、よほどの技術がある場合を除き、他の人のデバッグ済み実装を借用する方がはるかに良いです (java.util.concurrent パッケージには良い例がたくさん含まれています)。独自のアルゴリズムを作成する場合、誤ってバグが入り込みやすいことで知られています。
第 4 に、ミューテックスのスコープを広げると効果があります。ミューテックスを常にロックしたりロック解除したりするのではなく、単純にミューテックスを開いたままにしておくか、「より大きな」項目 (プロパティの 1 つではなくオブジェクトなど) をロックするかのどちらかです。 。ただし、これは非常に慎重に行う必要があります。この方法で簡単に問題を引き起こすことができます。
他のヒント
プログラムのスレッド モデルは、単一行を書き込む前に決定する必要があります。モジュールがプログラムの残りの部分と矛盾している場合、アプリケーションがクラッシュしたり、デッドロックが破損したりする可能性があります。
新しく始める余裕がある場合は、並列実行できるプログラムの大きな関数を特定し、スレッド プールを使用してタスクをスケジュールしてください。効率を高める秘訣は、可能な限りミューテックスを回避し、高レベルでのリソースの競合を避けるためにアプリを (再) コーディングすることです。