スレッド セーフなクラスとは、シリアル化がカプセル化されてクラスに隠されることを意味するため、シリアル実行を強制する機会が増え、パフォーマンスが低下します。
スレッド セーフをクライアントの責任にすることは、カプセル化を無効にします (常にではありません)。コンテキスト/設計に応じて、スレッドセーフは非常に複雑になるか、時間の経過とともに変化しやすくなる (API が変更されるとプログラムが壊れる) か、単純に統一されていない可能性があります。同期の抽象化は、損失と同等である必要はありません。また、特に初心者向けではないため、大きな利益をもたらす可能性もあります。
これらのクリティカル セクションは、より大きな (または最大の) 単位であるアプリケーション ロジックで管理することをお勧めします。
誰が言ったのかはわかりませんが、それは必ずしもすべてのシナリオにとって理想的ではありません。並行システムの実装に取り掛かると、設計内で同期の最適な粒度を選択することで、動作方法が大きく変わることに気付くでしょう。「最適な」一般的な設計が、特定の用途に常に最適であるとは限らないことに注意してください。
ここには厳密で迅速なルールはありません。多くの設計では、小さくて最短 (ただし、より多くのロックを使用および取得する可能性があります) の方が適していますが、最大ユニットでは競合が増加し、重大なブロッキングが発生する可能性があります。更新を開始してから、更新中に構造全体の持続的な同期を必要としない更新内の処理に多くの時間を費やすのは非常に簡単です。アクセスごとにグラフ全体をロックダウンすることが常に良いとは限りません。また、構造体の特定のコンポーネントは、他のコンポーネントから独立してスレッドセーフになる場合があります。したがって、最大単位のアプローチでは、特にサイズと複雑さが増大するにつれて、パフォーマンスに影響を与えるシリアライゼーションが強制される可能性が高くなります。
では、なぜ人々はスレッドセーフなクラスを必要とするのでしょうか? それらの本当の利点は何ですか?
いくつかの正当な理由が思い浮かびます。
それらを正しく実装し、診断し、テストするのは難しい場合があります。高性能並行設計は、講演に参加したり、いくつかのオンライン チュートリアルを行ったりして学んだ概念ではありません。優れた設計とは何かを理解するには、多くの間違いと時間を費やす必要があります。
一部の構造は非常に特殊化されています。これらは、ノンブロッキングであったり、アトミックに依存していたり、一般的ではない同時実行パターンや同期形式を使用している場合があります。例: デフォルトでは、ロックが必要なときにミューテックスに到達するだけかもしれませんが、rwlock または spinlock の方が優れている場合もあります。不変性の方が良い場合もあります。
一部のコンテキストまたはドメインは非常に専門的です。多くの場合、単一のコンポーネントを設計するのは簡単な作業ですが、システム全体を設計し、コンポーネントがどのように相互作用するかは、はるかに大きな課題であり、システムは特別な制約の下で動作する必要がある場合があります。その設計の同期に依存することで、頭痛の種を大幅に軽減できます。多くの異なるワークロードの下でベンチマークするのに時間をかけないかもしれませんが、それを書いた人は実装とその実行を理解するために時間を費やしました.
それだけで機能します。一部の人々は、並行性の問題に執着することにエネルギーを費やしたくありません。彼らはむしろ、実績のある信頼できる実装を使用し、プログラムの他の側面に集中したいと考えています。場合によっては、ソフトウェアを使用することになった人がこれらの概念の一部を十分に理解していない可能性があり、彼らが実績のある (または慣れ親しんだ) 設計を使用することを選択したときは、感謝するでしょう。
カプセル化。カプセル化により、同時実行システムのパフォーマンスが大幅に向上する場合があります。例: メンバーまたはパラメーターは条件付きで不変である場合があり、その特性が利用される場合があります。他の場合では、カプセル化により、取得率が低下したり、ブロッキングが減少したりする可能性があります。もう 1 つのケースは、カプセル化によってインターフェイスの使用の複雑さを軽減できる場合です。潜在的なスレッドの問題のカテゴリ全体が削除される可能性があります (ただし、制約のセットが少なくなる可能性があります)。
理解することが少ない。よく知られた実装を再利用して、その動作を理解すれば、手書きの実装 (たとえば、昨年退職した同僚) のレビューに比べて学ぶことが少なくてすみます。
もちろん欠点もありますが、それはあなたの問題ではありません;)