1

現在、HashtableとしてラップされたHashtableを使用しています。マルチスレッド環境(asp.netなど)で使用できるライブラリ内の単純なキャッシュとして同期されています。これは、このコレクションに適した使用法ですか?.Net 4.0で利用できるより適切な構成があることは理解していますが、.Net3.5で立ち往生しています。

違いが生じる場合、このキャッシュは頻繁に読み取られ、非常にまれに書き込まれます(ただし、スレッドセーフを維持する必要があります)。

基本的な使用法は、次のようなものです。

Private Shared ReadOnly ExpressionCache As Hashtable = Hashtable.Synchronized(New Hashtable())

..snip...

If Not ExpressionCache.ContainsKey(myKey) Then
      ExpressionCache(myKey) = myExpensiveOperationToInit()
End If
Return  ExpressionCache(myKey)

..snip..

私はここで潜在的に危険なことをしていますか、それともこれは許容できるユースケースですか?

4

1 に答える 1

4

実際、Hashtable(とは異なりDictionary<,>)キャッシュとして使用するための非常に優れたスレッドセマンティクスがすでにあります。リーダーにとってはスレッドセーフです(ただし、ライターに対してはロックが必要です)-MSDNから

ハッシュテーブルは、複数のリーダースレッドと単一の書き込みスレッドで使用するためのスレッドセーフです。スレッドの1つだけが書き込み(更新)操作を実行する場合、マルチスレッドでの使用に対してスレッドセーフです。これにより、ライターがハッシュテーブルにシリアル化されている場合にロックフリーの読み取りが可能になります。

.Synchronized(複数のライターをサポートすることについても言及していますが、率直に言って、これを自分で制御すると、通常、はるかに良い結果が得られます)

ただし、ファントム読み取りを回避するために、個別の「含む」/「取得」操作を使用しないでください。標準的な使用法は次のとおりです(例としてC#を使用):

public YourType Get(string key) {
    return (YourType) expressionCache[key];
}
public void Set(string key, YourType value) {
    lock(expressionCache) {
        expressionCache[key] = value;
    }
}

キーポイント:

  • 「セット」のみにロックがあります
  • 「get」での1回の操作のみ
  • セット内で、ではなくインデクサーを使用しAddます(その後、最初に「含む」をチェックする必要はありません)

ラッパーは、.Synchronizedほとんどの一般的なスレッドシナリオでは実際にはほとんど価値がありません。

于 2012-09-23T18:40:59.800 に答える