.NET 6 PriorityQueue 线程安全吗?

Posted

技术标签:

【中文标题】.NET 6 PriorityQueue 线程安全吗?【英文标题】:Is .NET 6 PriorityQueue thread-safe? 【发布时间】:2021-12-27 09:40:21 【问题描述】:

.NET 6 现在有PriorityQueue<TElement,TPriority>,这非常有用。该文档还不是很清楚(在提出问题时授予该文档仍然适用于 RC1)它是否是线程安全的。两件事:

它位于System.Collections.Generic 中,而System.Collections.Concurrent 中似乎没有等价物。

它确实有名为TryDequeueTryPeek 的方法。当然,它们可能只是在队列为空时不会抛出异常的方法,但它确实给人一种并发集合的印象。

我可以将它用于多线程环境而不进行包装/锁定(例如在 ASP.NET Core 网站中)吗?任何我不知道的并发等效项(如果可能,我尽量不使用 3rd-party 包)?

【问题讨论】:

这有点遗漏——通常 MSDN 文档擅长说明一个类型是否是线程安全的。然而,看看the source,很明显它不是线程安全的。您将需要使用自己的锁定。 在我看来,最简单的规则是,如果类型没有明确声明它是线程安全的(或者有暗示它的名称),你应该假设它不是. 这不仅是您的规则 - 它是编写 .NET 的一般方式。线程安全是一项罕见的功能,需要付出一定的代价。除非明确提及,否则默认情况下某些东西不是线程安全的。因此,文档非常清楚这不是线程安全的。 没有。着眼于大局,PriorityQueue 的重点是迭代。您按优先顺序取回元素。迭代永远不是线程安全的。安全集合类通过让枚举器复制集合来伪造它,这只会使其在逻辑上安全。但是很昂贵,并且不会阻止不再出现在集合中的元素出现。只有使用 lock 的客户端代码才能使其真正安全,小心锁定迭代器循环的痛苦。 【参考方案1】:

例如,查看PriorityQueue.Enqueue 的source code,很明显代码不是线程安全的:

public void Enqueue(TElement element, TPriority priority)

    // Virtually add the node at the end of the underlying array.
    // Note that the node being enqueued does not need to be physically placed
    // there at this point, as such an assignment would be redundant.

    int currentSize = _size++; // <-- BOOM

【讨论】:

【参考方案2】:

文档还不是很清楚

确实如此。 .NET 中的任何内容都不是线程安全的,除非文档中明确提及。期间。

线程安全伴随着(显着的)性能开销,尤其是在一般情况下(即不假设特定用途)。因此,让所有线程安全“以防万一”将是非常愚蠢的。因此,.NET 中的一般概念(从 1.0 开始)认为没有什么是线程安全的,除非在文档中明确提及。

正如你所说,文档没有提到线程安全。因此,非常清楚不是线程安全的。

【讨论】:

如果这通过遗漏非常清楚,那么所有具有“线程安全”部分的类型都说“这不是线程安全的”,例如非优先Queue&lt;T&gt; class?由于 MSDN 文档中的总体约定是有一个“线程安全”部分,无论该类型是否是线程安全的,因此缺少任何此类部分更多地表明该类型不是线程安全的...... 这需要对 .NET 文档有广泛的了解,即不是很明显。

以上是关于.NET 6 PriorityQueue 线程安全吗?的主要内容,如果未能解决你的问题,请参考以下文章

.NET 6 优先队列 PriorityQueue 实现分析

.NET 6新特性试用 | PriorityQueue

源码阅读(37):Java中线程安全的QueueDeque结构——PriorityBlockingQueue

源码阅读(37):Java中线程安全的QueueDeque结构——PriorityBlockingQueue

PriorityQueue 源码分析

JDK源码分析-PriorityBlockingQueue