首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ConcurrentQueue ToList() vs ToArray().ToList()

ConcurrentQueue ToList() vs ToArray().ToList()
EN

Stack Overflow用户
提问于 2018-01-31 12:39:01
回答 1查看 3K关注 0票数 4

我对此不是百分之百,所以我想要专家的意见。

代码语言:javascript
复制
ConcurrentQueue<object> queue = new ConcurrentQueue<object>();

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

我知道ToArray()方法会创建一个副本(因为它是ConcurrentQueue中的一个内部方法),但是直接调用ToList()方法会做同样的事情吗?

简单地说,将代码从A重构为B安全吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-01-31 13:02:58

如果我们查看源代码,我们将看到GetEnumerator也是线程安全的,所以我认为A和B都是线程安全的。

当您调用.ToList() Linq时,调用列表的构造函数

代码语言:javascript
复制
 public List(IEnumerable<T> collection) {

因此,代码实际上使副本看起来像线程安全:

代码语言:javascript
复制
        using(IEnumerator<T> en = collection.GetEnumerator()) {
            while(en.MoveNext()) {
                Add(en.Current);                                    
            }

ConcurrentQueue源代码

清单源代码

代码语言:javascript
复制
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);
}

枚举器的评论还说,我们可以同时使用它:

代码语言:javascript
复制
    /// 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.
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48542439

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档