.net Hashtable.Synchronized是否适合在多线程环境中用作简单缓存?
我目前正在使用包装为哈希表的哈希表。同步为库中可由多线程环境(如asp.net)使用的简单缓存-这是否适合用于此集合?我知道在.NET4.0中有更多合适的结构可用,但我还是坚持使用.NET3.5 如果有什么不同的话,这个缓存经常被读取,很少被写入(但需要保持线程安全) 基本用法大致如下:.net Hashtable.Synchronized是否适合在多线程环境中用作简单缓存?,.net,collections,hashtable,.net,Collections,Hashtable,我目前正在使用包装为哈希表的哈希表。同步为库中可由多线程环境(如asp.net)使用的简单缓存-这是否适合用于此集合?我知道在.NET4.0中有更多合适的结构可用,但我还是坚持使用.NET3.5 如果有什么不同的话,这个缓存经常被读取,很少被写入(但需要保持线程安全) 基本用法大致如下: Private Shared ReadOnly ExpressionCache As Hashtable = Hashtable.Synchronized(New Hashtable()) ..snip...
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..
我在这里做了一些潜在危险的事情,还是这是一个可接受的用例?事实上,
哈希表(与字典
不同)已经具有非常好的线程语义,可以用作缓存:它对读卡器是线程安全的(但对写卡器需要锁定)——:
Hashtable是线程安全的,可供多个读取器线程和单个写入线程使用。当只有一个线程执行写(更新)操作时,多线程使用它是线程安全的,这允许在将写入程序序列化到哈希表的情况下进行无锁读取
(它还提到了支持多个编写器的.Synchronized
,但坦率地说,自己控制这一点通常会带来更好的结果)
但是,为了避免幻象读取,您不应该使用单独的“包含”/“获取”操作;标准用法可能是(例如使用C#):
要点:
- 只有“集合”有任何锁定
- “get”中只有一个操作
- 在集合中使用索引器,而不是
Add
(这样您就不需要先选中“contains”)
.Synchronized
包装在大多数常见的线程场景中实际上没有什么价值。事实上,哈希表(与字典
不同)已经具有非常好的线程语义,可以用作缓存:它对读卡器来说是线程安全的(但对写卡器来说需要锁定)——:
Hashtable是线程安全的,可供多个读取器线程和单个写入线程使用。当只有一个线程执行写(更新)操作时,多线程使用它是线程安全的,这允许在将写入程序序列化到哈希表的情况下进行无锁读取
(它还提到了支持多个编写器的.Synchronized
,但坦率地说,自己控制这一点通常会带来更好的结果)
但是,为了避免幻象读取,您不应该使用单独的“包含”/“获取”操作;标准用法可能是(例如使用C#):
要点:
- 只有“集合”有任何锁定
- “get”中只有一个操作
- 在集合中使用索引器,而不是
Add
(这样您就不需要先选中“contains”)
.Synchronized
包装器在大多数常见的线程场景中实际上没有什么价值;我只是想澄清一下,在多线程场景中使用.Synchronized包装器有什么问题吗?即使它不是最优化的方法?@DanP不,它也会起作用-但是:如果你小心的话,你可以不加锁地进行读取。或者可能是双重检查锁定,即var tmp=(YourType)expressionCache[key];if(tmp==null)lock(expressionCache){tmp=(YourType)expressionCache[key];if(tmp==null){tmp=GetNewValue();expressionCache[key]=tmp;}}返回tmp
@BlamDictionary
不支持“7个读卡器加一个写卡器”的场景,尽管它支持“7个读卡器”或(独占)“1个写卡器”。这意味着,如果使用字典
,则必须使用完全独占锁(例如锁
aka监视器
),或者类似于ReaderWriterLockSlim
。哈希表
的无锁方法更具可伸缩性。感谢您提供了非常有用的答案;我只是想澄清一下,在多线程场景中使用.Synchronized包装器有什么问题吗?即使它不是最优化的方法?@DanP不,它也会起作用-但是:如果你小心的话,你可以不加锁地进行读取。或者可能是双重检查锁定,即var tmp=(YourType)expressionCache[key];if(tmp==null)lock(expressionCache){tmp=(YourType)expressionCache[key];if(tmp==null){tmp=GetNewValue();expressionCache[key]=tmp;}}返回tmp
@BlamDictionary
不支持“7个读卡器加一个写卡器”的场景,尽管它支持“7个读卡器”或(独占)“1个写卡器”。这意味着,如果使用字典
,则必须使用完全独占锁(例如锁
aka监视器
),或者类似于ReaderWriterLockSlim
。哈希表
可能采用的无锁方法更具可伸缩性。
public YourType Get(string key) {
return (YourType) expressionCache[key];
}
public void Set(string key, YourType value) {
lock(expressionCache) {
expressionCache[key] = value;
}
}