简体   繁体   English

ConcurrentDictionary <TKey,TValue> vs词典 <TKey,TValue>

[英]ConcurrentDictionary<TKey,TValue> vs Dictionary<TKey,TValue>

As MSDN says 正如MSDN所说

ConcurrentDictionary<TKey, TValue> Class Represents a thread-safe collection of key-value pairs that can be accessed by multiple threads concurrently. ConcurrentDictionary<TKey, TValue> Class表示可以由多个线程同时访问的键值对的线程安全集合。

But as I know, System.Collections.Concurrent classes are designed for PLINQ. 但据我所知, System.Collections.Concurrent类是为PLINQ设计的。

I have Dictionary<Key,Value> which keeps on-line clients in the server, and I make it thread safe by locking object when I have access to it. 我有Dictionary<Key,Value> ,它保留了服务器中的在线客户端,并且当我有权访问它时,我通过锁定对象使其成为线程安全的。

Can I safely replace Dictionary<TKey,TValue> by ConcurrentDictionary<TKey,TValue> in my case? 在我的情况下,我可以通过ConcurrentDictionary<TKey,TValue>安全地替换Dictionary<TKey,TValue>吗? will the performance increased after replacement? 更换后性能会提高吗?

Here in Part 5 Joseph Albahari mentioned that it designed for Parallel programming 这里在第5约瑟夫阿尔巴哈利提到,它专为并行编程

  • The concurrent collections are tuned for parallel programming. 并发集合针对并行编程进行了调整。 The conventional collections outperform them in all but highly concurrent scenarios. 除了高度并发的场景外,传统的集合在所有集合中都优于它们。
  • A thread-safe collection doesn't guarantee that the code using it will be thread-safe. 线程安全的集合不保证使用它的代码是线程安全的。
  • If you enumerate over a concurrent collection while another thread is modifying it, no exception is thrown. 如果在另一个线程正在修改它时枚举并发集合,则不会抛出任何异常。 Instead, you get a mixture of old and new content. 相反,你会得到新旧内容的混合。
  • There's no concurrent version of List. List没有并发版本。
  • The concurrent stack, queue, and bag classes are implemented internally with linked lists. 并发堆栈,队列和包类在内部使用链接列表实现。 This makes them less memory-efficient than the nonconcurrent Stack and Queue classes, but better for concurrent access because linked lists are conducive to lock-free or low-lock implementations. 这使得它们比非并发Stack和Queue类的内存效率更低,但对并发访问更好,因为链表有利于无锁或低锁实现。 (This is because inserting a node into a linked list requires updating just a couple of references, while inserting an element into a List-like structure may require moving thousands of existing elements.) (这是因为将节点插入链表需要更新几个引用,而将元素插入类似List的结构可能需要移动数千个现有元素。)

Without knowing more about what you're doing within the lock, then it's impossible to say. 如果不知道你在锁中做了什么,那就不可能说了。

For instance, if all of your dictionary access looks like this: 例如,如果您的所有字典访问都如下所示:

lock(lockObject)
{
    foo = dict[key];
}

... // elsewhere

lock(lockObject)
{
    dict[key] = foo;
}

Then you'll be fine switching it out (though you likely won't see any difference in performance, so if it ain't broke, don't fix it). 然后你可以将它切换出来(虽然你可能不会看到性能上的任何差异,所以如果没有破坏,不要修复它)。 However, if you're doing anything fancy within the lock block where you interact with the dictionary, then you'll have to make sure that the dictionary provides a single function that can accomplish what you're doing within the lock block, otherwise you'll end up with code that is functionally different from what you had before. 但是,如果您在与字典交互的锁定块中执行任何操作,那么您必须确保字典提供单个函数,该函数可以完成您在锁定块中所执行的操作,否则您最终会得到与以前功能不同的代码。 The biggest thing to remember is that the dictionary only guarantees that concurrent calls to the dictionary are executed in a serial fashion; 要记住的最重要的事情是字典只保证对字典的并发调用以串行方式执行; it can't handle cases where you have a single action in your code that interacts with the dictionary multiple times. 它无法处理您的代码中有多个与字典交互的单个操作的情况。 Cases like that, when not accounted for by the ConcurrentDictionary , require your own concurrency control. 这样的情况,当不被ConcurrentDictionary ,需要你自己的并发控制。

Thankfully, the ConcurrentDictionary provides some helper functions for more common multi-step operations like AddOrUpdate or GetOrAdd , but they can't cover every circumstance. 值得庆幸的是, ConcurrentDictionary为更常见的多步操作(如AddOrUpdateGetOrAdd提供了一些辅助函数,但它们无法涵盖所有​​情况。 If you find yourself having to work to shoehorn your logic into these functions, it may be better to handle your own concurrency. 如果你发现自己不得不把你的逻辑搞砸到这些函数中,那么处理你自己的并发可能会更好。

It's not as simple as replacing Dictionary with ConcurrentDictionary , you'll need to adapt your code, as these classes have new methods that behave differently, in order to guarantee thread-safety. 它不像用ConcurrentDictionary替换Dictionary那么简单,你需要调整你的代码,因为这些类有新的方法行为不同,以保证线程安全。

Eg., instead of calling Add or Remove , you have TryAdd and TryRemove . 例如,而不是调用AddRemove ,你有TryAddTryRemove It's important you use these methods that behave atomically, as if you make two calls where the second is reliant on the outcome of the first, you'll still have race conditions and need a lock . 重要的是你使用这些原子行为的方法,就像你进行两次调用,其中第二次依赖于第一次的结果,你仍然会有竞争条件并需要lock

You can replace Dictionary<TKey, TValue> with ConcurrentDictionary<TKey, TValue> . 您可以使用ConcurrentDictionary<TKey, TValue>替换Dictionary<TKey, TValue> ConcurrentDictionary<TKey, TValue>

The effect on performance may not be what you want though (if there is a lot of locking/synchronization, performance may suffer...but at least your collection is thread-safe). 对性能的影响可能不是你想要的(如果有很多锁定/同步,性能可能会受到影响......但至少你的集合是线程安全的)。

While I'm unsure about replacement difficulties, but if you have anywhere where you need to access multiple elements in the dictionary in the same "lock session" then you'll need to modify your code. 虽然我不确定替换困难,但如果你有任何地方需要在相同的“锁定会话”中访问字典中的多个元素,那么你将需要修改你的代码。

It could give improved performance if Microsoft has given separate locks for read and write, since read operations shouldn't block other read operations. 如果Microsoft为读写提供了单独的锁,它可以提高性能,因为读操作不应该阻止其他读操作。

Yes you can safely replace, however dictionary designed for plinq may have some extra code for added functionality that you may not use. 是的,您可以安全地替换,但是为plinq设计的字典可能有一些额外的代码,用于添加您可能不使用的功能。 But the performance overhead will be marginally very small. 但性能开销将略微很小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM