可移植.NET框架中并发集合的类似物
将代码移动到可移植框架中,我发现在可移植类库(PCL)中根本没有可用的并发集合,这很好地解释了这一点 但我仍然需要并发字典模拟才能在那里运行。可移植.NET框架中并发集合的类似物,.net,silverlight,collections,concurrency,portable-class-library,.net,Silverlight,Collections,Concurrency,Portable Class Library,将代码移动到可移植框架中,我发现在可移植类库(PCL)中根本没有可用的并发集合,这很好地解释了这一点 但我仍然需要并发字典模拟才能在那里运行。 与修改性能相比,我对读取/包含性能更感兴趣。字典集合的最大好处是快速键访问和快速包含评估。 所有字典都使用不同的复杂算法(请检查此项),从头开始编写自己的字典将非常困难 所以,我尝试重用源代码的原始ConcurrentDictionary从(您可以为每个基类)。 但是,它非常复杂,并且使用几十个私有类和低级函数来管理内存。这不是偶然的,它从一开始就在PC
与修改性能相比,我对读取/包含性能更感兴趣。字典集合的最大好处是快速键访问和快速包含评估。 所有字典都使用不同的复杂算法(请检查此项),从头开始编写自己的字典将非常困难 所以,我尝试重用源代码的原始ConcurrentDictionary从(您可以为每个基类)。 但是,它非常复杂,并且使用几十个私有类和低级函数来管理内存。这不是偶然的,它从一开始就在PCL中不可用:) 第二个想法是制作普通字典的包装器,并在每个方法调用中添加锁部分。尽管关键部分并不昂贵,但它导致了性能的急剧下降 因此,我以Dictionary包装器的清晰互锁实现作为结束。通常情况下,普通字典支持从不同线程读取和枚举,只要不同时修改。 所以,每一次改变,我们都会克隆所有的字典。所有在这段时间内读取它的线程都将继续迭代较旧的副本
public class InterlockedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
private Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
public TValue this[TKey key]
{
get
{
return _dictionary[key];
}
set
{
ApplyAndChange(dict => dict[key] = value);
}
}
public Dictionary<TKey, TValue>.KeyCollection Keys
{
get
{
return _dictionary.Keys;
}
}
public Dictionary<TKey, TValue>.ValueCollection Values
{
get
{
return _dictionary.Values;
}
}
public int Count
{
get
{
return _dictionary.Count;
}
}
public void Add(KeyValuePair<TKey, TValue> item)
{
ApplyAndChange(dict => dict.Add(item.Key, item.Value));
}
public void Clear()
{
_dictionary = new Dictionary<TKey, TValue>();
}
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}
public void Add(TKey key, TValue value)
{
ApplyAndChange(dict => dict.Add(key, value));
}
public bool Remove(TKey key)
{
bool result = false;
ApplyAndChange(dict => result = dict.Remove(key));
return result;
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dictionary.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private void ApplyAndChange(Action<Dictionary<TKey, TValue>> action)
{
Dictionary<TKey, TValue> initialDictionary, updatedDictionary, replacedDictionary;
do
{
initialDictionary = _dictionary;
updatedDictionary = new Dictionary<TKey, TValue>(initialDictionary);
action(updatedDictionary);
} while (Interlocked.CompareExchange(ref _dictionary, updatedDictionary, initialDictionary) != initialDictionary);
}
}
公共类InterlocatedDictionary:IEnumerable
{
专用词典_Dictionary=新词典();
公共TValue此[TKey]
{
得到
{
返回字典[键];
}
设置
{
ApplyAndChange(dict=>dict[key]=value);
}
}
public Dictionary.KeyCollection密钥
{
得到
{
返回_dictionary.Keys;
}
}
public Dictionary.ValueCollection值
{
得到
{
返回_dictionary.Values;
}
}
公共整数计数
{
得到
{
返回_dictionary.Count;
}
}
公共作废添加(KeyValuePair项)
{
ApplyAndChange(dict=>dict.Add(item.Key,item.Value));
}
公共空间清除()
{
_字典=新字典();
}
公共bool ContainsKey(TKey)
{
返回_dictionary.ContainsKey(key);
}
公共无效添加(TKey键,TValue值)
{
ApplyAndChange(dict=>dict.Add(key,value));
}
公用门移除(TKey)
{
布尔结果=假;
ApplyAndChange(dict=>result=dict.Remove(key));
返回结果;
}
公共IEnumerator GetEnumerator()
{
返回_dictionary.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
返回GetEnumerator();
}
私有无效应用程序更改(操作)
{
字典初始字典、更新字典、替换字典;
做
{
initialDictionary=\u字典;
updatedDictionary=新字典(初始字典);
行动(更新的对话);
}while(interlocated.compareeexchange(ref _dictionary,updatedictionary,initialDictionary)!=initialDictionary);
}
}
这个实现没有实现IDictionary,因为那里有很多非必需的成员。但是,通过直接为所有非修改方法调用底层字典,并使用ApplyAndChange(dict=>…)
包装所有修改方法,可以很容易地实现这一点
注意:就性能而言,与原始字典相比,此实现的Set、Add和Remove以及equal to Read和Contains性能更差。如果您对阅读更感兴趣,您应该使用
ReaderWriterLockSlim
这是一个锁定原语,允许多个读卡器或一个写卡器在任何给定时间进入关键区域。当字典被多个线程读取时,这实际上不会导致性能下降,并且仅当线程尝试写入时才应用互斥
您可以这样实现它(为了简洁起见,我省略了大多数方法-我留下了Add
作为编写器示例,而Contains
作为读者示例):
如果所有非联锁操作都是原子操作,那么这将是线程安全的,但它们不是原子操作。在索引器
集中
,可以在\u字典的行之间更改\u字典。ContainsKey(key)
和\u字典[key]=值代码>。此解决方案不是线程安全的。我相信ReaderWriterLockSlim
是一个更好的解决方案-您将获得大致相同的性能,但使用的方法不太容易出错。无锁代码很容易被破坏。@dcastro我试过ReaderWriterLockSlim,发现与无锁解决方案相比,性能大幅下降。不过,这可能是针对我的情况。我喜欢这个ReaderWriterLockSlim解决方案,它简单明了。
public class CustomDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private readonly IDictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
public bool Contains(KeyValuePair<TKey, TValue> item)
{
_lock.EnterReadLock();
try
{
return _dictionary.Contains(item);
}
finally
{
_lock.EnterReadLock();
}
}
public void Add(KeyValuePair<TKey, TValue> item)
{
_lock.EnterWriteLock();
try
{
_dictionary.Add(item);
}
finally
{
_lock.ExitWriteLock();
}
}
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
_lock.EnterReadLock();
try
{
foreach (var entry in _dictionary)
yield return entry;
}
finally
{
_lock.ExitReadLock();
}
}