gpt4 book ai didi

c# - ConcurrentQueue ToList() 与 ToArray().ToList()

转载 作者:行者123 更新时间:2023-11-30 15:55:31 29 4
gpt4 key购买 nike

我对此不是 100%,所以我需要专家的意见。

ConcurrentQueue<object> queue = new ConcurrentQueue<object>();

List<object> listA = queue.ToArray().ToList(); // A
List<object> listB = queue.ToList(); // B

我知道 ToArray() 方法会进行复制(因为它是 ConcurrentQueue 中的内部方法),但会调用 ToList() 方法直接做同样的事情?

简单地说,将代码从 A 重构到 B 是否安全?

最佳答案

如果我们查看源代码,我们会发现 GetEnumerator 也是线程安全的,所以我假设 A 和 B 都是线程安全的。

当您调用 .ToList() Linq 调用 List 的构造函数时

 public List(IEnumerable<T> collection) {

所以代码实际上是让副本看起来像线程安全的:

        using(IEnumerator<T> en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Add(en.Current);
}

source code of ConcurrentQueue

source code of List

public IEnumerator<T> GetEnumerator()
{
// Increments the number of active snapshot takers. This increment must happen before the snapshot is
// taken. At the same time, Decrement must happen after the enumeration is over. Only in this way, can it
// eliminate race condition when Segment.TryRemove() checks whether m_numSnapshotTakers == 0.
Interlocked.Increment(ref m_numSnapshotTakers);

// Takes a snapshot of the queue.
// A design flaw here: if a Thread.Abort() happens, we cannot decrement m_numSnapshotTakers. But we cannot
// wrap the following with a try/finally block, otherwise the decrement will happen before the yield return
// statements in the GetEnumerator (head, tail, headLow, tailHigh) method.
Segment head, tail;
int headLow, tailHigh;
GetHeadTailPositions(out head, out tail, out headLow, out tailHigh);

//If we put yield-return here, the iterator will be lazily evaluated. As a result a snapshot of
// the queue is not taken when GetEnumerator is initialized but when MoveNext() is first called.
// This is inconsistent with existing generic collections. In order to prevent it, we capture the
// value of m_head in a buffer and call out to a helper method.
//The old way of doing this was to return the ToList().GetEnumerator(), but ToList() was an
// unnecessary perfomance hit.
return GetEnumerator(head, tail, headLow, tailHigh);
}

枚举器的备注也说我们可以并发使用:

    /// The enumeration represents a moment-in-time snapshot of the contents
/// of the queue. It does not reflect any updates to the collection after
/// <see cref="GetEnumerator"/> was called. The enumerator is safe to use
/// concurrently with reads from and writes to the queue.

关于c# - ConcurrentQueue ToList() 与 ToArray().ToList(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48542439/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com