【问题标题】:Sorting a ConcurrentDictionary by Value按值对 ConcurrentDictionary 进行排序
【发布时间】:2011-12-22 19:25:10
【问题描述】:

我可以像这样按值对我的 ConcurrentDictionary 进行排序:

static ConcurrentDictionary<string, Proxy> Proxies = 
    new ConcurrentDictionary<string, Proxy>();

Proxies.OrderBy(p => p.Value.Speed);

这很好,除了我想将新的重新排序列表设置为字典,有效地对字典本身进行排序,而不仅仅是接收排序项目的结果列表。

我尝试做这样的事情但没有运气 - 之后字典仍然无序:

Proxies = new ConcurrentDictionary<string,Proxy>(
    Proxies.OrderBy(p => p.Value.Speed));

似乎这样做对字典没有影响。我还尝试将 OrderBy 结果转换为一个新的 var,认为它可能会对委托产生影响,但仍然没有运气。

如何重新排序这个 ConcurrentDictionary,然后强制字典成为 OrderBy 的重新排序结果?

【问题讨论】:

  • 如果您需要字典的快速访问属性,结合线程安全和连续排序,您需要类似并发 B-tree 的东西。我不相信.NET 中有一个现成的。也许是第三方?有没有机会在需要结果时使用 OrderBy()?

标签: c# c#-4.0 concurrency parallel-processing concurrent-programming


【解决方案1】:

简单字典不是排序集合。它们只是一个将键映射到值的集合。 ConcurrentDictionary 也不例外。

您需要一个 SortedConcurrentDictionary(类似于 SortedDictionary),但是,此数据结构不存在。

至于如果您确实需要排序的“字典”,我们需要了解更多关于您的用例的信息。这是一个虚假的优先级队列吗?您可以简单地使用ConcurrentBag&lt;Proxy&gt; 并在事后执行订购吗?

如果您需要收集集合并在下游并行方法中按排序顺序使用代理,我建议您考虑创建一个custom Partitioner,可能会借鉴MSDN example of an OrderablePartitioner

【讨论】:

  • 字典仅用于防止添加重复值。以前,我只是使用 List 并在添加之前检查值是否存在。我可以使用 ConcurrentBag 但这需要使用两个单独的列表,因为我在 ListView 中保持代理的主动可见和维护视图,从而允许查看/管理/等代理。以前使用锁定机制的 List 实现工作得相当好,直到我最近遇到了一个存在空项目的错误,所以我尝试切换到 ConcurrentBag/Dictionary/etc...
  • 所以听起来你需要一个并发的HashSet,而ConcurrentBag 不是你找到的。这是并发的,因为另一个线程来更新它吗?
  • Rgiht,我正在使用多个线程来检查代理并相应地更新列表。
  • 所以没有人会花 2 个小时来实现一个 HashSet 和一个 List 来充当“排序”查看器:.NET 4.0 添加了一个“SortedSet”一个排序的 HashSet。 /smash-face-on-keyboard
  • 我在核心 2.2 中也使用并发字典来处理线程安全方面,我检查了加载和访问以验证列表是否符合我期望的顺序(迭代每个项目) .不完美,但它似乎表明加载顺序是它保持不变的方式。
【解决方案2】:

如果你经常在不可变类中调用它可能效率不高,但很简单:

Imports System.Collections.Concurrent

Public Class SortedConcurrentDictionary(Of TKey, Tvalue)
Inherits ConcurrentDictionary(Of TKey, Tvalue)

    Shadows ReadOnly Property Values As IEnumerable(Of Tvalue)
        Get
            If MyBase.Values.Count = 0 Then
                Return MyBase.Values
            End If
            Return From k In Keys Order By k Select Me(k)
        End Get
    End Property
End Class

【讨论】:

  • 有趣的想法,但性能如何?似乎键是按内容的每个枚举排序的?
  • @Eniola 你说的很对,就像我说的,“也许效率不高”。更复杂的版本会缓存并在字典更改时刷新缓存。
【解决方案3】:

字典,尤其是 ConcurrentDictionary,本质上是未排序的。

如果您需要排序集合,则需要将值存储为其他类型,例如 SortedDictionary&lt;T,U&gt;

【讨论】:

  • 不过,我希望利用 ConcurrentDictionary 提供的内置 .NET 并发。我可以看到在提供排序功能时这是不可能的。回到使用 lock() 语句...谢谢。
  • @user1111380 请注意 - 排序和并发集合通常会发生冲突... 通常,(如果可能)最好在处理数据时将数据保存在并发集合中,然后提取项目按特定顺序呈现结果等。
  • 但是以给定的顺序检索项目,其中使用集合的读取密集度高于写入密集度可能相当昂贵。我看到了一个想要更新 ConcurrentDictionary 并让项目的排序成为更新的原子部分的案例。而不必以所需的排序顺序重新初始化整个字典。为此,在 BCL 中使用 ConcurrentSortedDictionary 或 SortedConcurrentDictionary 将是一个不错的选择。
【解决方案4】:

ConcurrentDictionaryDictionary 一样,不知道排序的概念,即不包含任何排序信息。 OrderBy() 的结果有一个特定的订单,但是当分配给Proxies 时,订单信息会丢失。

注意IDictionary有排序实现,即SortedDictionarySortedList

【讨论】:

  • 这当然是 BCL 团队可以调查的问题?
【解决方案5】:

解决方案是使用SortedSet&lt;T&gt;,这是经过数小时的研究和代码修改后发现的。排序集提供 DictionaryHashSet 的唯一性,但也允许排序 - DictionaryHashSet 都不允许排序。

【讨论】:

  • 除了SortedSet不是并发的?我认为拥有一个支持排序和并发的集合是我们工具包中必不可少的一项。我认为我们应该鼓励 BCL 团队看看这个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-27
  • 2019-05-23
  • 1970-01-01
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多