.NET 6 PriorityQueue是线程安全的吗?

cgyqldqp  于 2023-04-13  发布在  .NET
关注(0)|答案(3)|浏览(171)

.NET 6现在有PriorityQueue<TElement,TPriority>,这是非常有用的。文档还不是很清楚(在问题的时候,文档仍然是RC 1的)如果它是线程安全的或不是。两件事:

  • 它驻留在System.Collections.Generic中,在System.Collections.Concurrent中似乎没有等效的。
  • 它确实有一个名为TryDequeueTryPeek的方法。当然,它们可能只是在队列为空时不会抛出异常的方法,但它确实给予人一种并发集合的印象。

我可以在没有 Package /锁定的情况下将其用于多线程环境吗(例如在ASP.NET Core网站中)?是否有我不知道的并发等价物(如果可能的话,我尽量不使用第三方包)?

j8ag8udp

j8ag8udp1#

例如,查看一下PriorityQueue.Enqueue的源代码,就可以立即看出该代码不是线程安全的:

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
o7jaxewo

o7jaxewo2#

文件还不是很清楚
实际上是的。.NET中的任何东西都不是线程安全的,除非在文档中明确提到。句号。
线程安全带来了(显著的)性能开销,特别是当一般性地完成时(即不假设特定用途)。因此,“以防万一”使所有内容都是线程安全的是非常愚蠢的。因此.NET中的一般概念(从1.0开始),除非在文档中明确提到,否则没有任何东西是线程安全的。
正如你所说的,文档中没有提到线程安全。因此,它非常清楚不是线程安全的。

puruo6ea

puruo6ea3#

它不是线程安全的。下面是一个非常简单的测试:

PriorityQueue<int, int> queue = new PriorityQueue<int, int>();
Parallel.For(0, 10000, (id) => {
    queue.Enqueue(id, 0);
    queue.Dequeue();
});

测试因异常而崩溃。可以使用lock语句轻松修复:

PriorityQueue<int, int> queue = new PriorityQueue<int, int>();
Parallel.For(0, 10000, (id) => {
    lock(queue)
    {
        queue.Enqueue(id, 0);
    }
    lock(queue)
    {
        queue.Dequeue();
    }
});

如果队列是共享的,这可能会导致问题,但可以通过使用扩展PriorityQueue的 Package 器类来修复,重写每个方法以包括锁。

相关问题