我很高兴看到.Net 4.0中新的System.Collections.Concurrent名称空间,非常好!我见过ConcurrentDictionary,ConcurrentQueue,ConcurrentStack,ConcurrentBag和BlockingCollection。
有一样东西似乎神秘地丢失了,那就是ConcurrentList<T>。我是不是必须自己写(或者从网上下载: )?
我是不是漏掉了什么明显的东西?
发布于 2015-06-11 08:57:57
在读取数量远远超过写入数量,或者(无论多么频繁)写入是非并发的情况下,写入时拷贝方法可能是合适的。
如下所示的实现是
var snap = _list; snap[snap.Count - 1];永远不会(当然,除了一个空的列表)抛出,并且您还可以免费获得带有快照语义的线程安全枚举。我是多么爱immutability!中的
为了让写时复制起作用,你必须保持你的数据结构实际上是不可变的,也就是说,在你让它们对其他线程可用之后,任何人都不能改变它们。当您想要修改时,您可以
在reference to
中,对clone
代码
static class CopyOnWriteSwapper
{
public static void Swap<T>(ref T obj, Func<T, T> cloner, Action<T> op)
where T : class
{
while (true)
{
var objBefore = Volatile.Read(ref obj);
var newObj = cloner(objBefore);
op(newObj);
if (Interlocked.CompareExchange(ref obj, newObj, objBefore) == objBefore)
return;
}
}
}使用
CopyOnWriteSwapper.Swap(ref _myList,
orig => new List<string>(orig),
clone => clone.Add("asdf"));如果你需要更高的性能,这将有助于取消泛化方法,例如为每种类型的修改(添加、删除等)创建一个方法。并对函数指针cloner和op进行硬编码。
N.B. #1你有责任确保没有人修改(假设)不可变的数据结构。我们无法在泛型实现中阻止这种情况发生,但是当专门针对List<T>时,您可以防止使用List.AsReadOnly()进行修改
N.B. #2注意列表中的值。上面的写时复制方法只保护它们的列表成员身份,但是如果你没有把字符串放在其中,而是放了一些其他的可变对象,你必须注意线程的安全(例如锁定)。但这与这个解决方案是正交的,例如,锁定可变的值可以很容易地使用,而不会出现问题。你只需要意识到这一点。
注意事项#3如果您的数据结构很大,并且您经常修改它,则在内存消耗和复制所涉及的CPU成本方面,写入时复制方法可能都是令人望而却步的。在这种情况下,您可能希望使用MS的Immutable Collections。
https://stackoverflow.com/questions/6601611
复制相似问题