Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is LINQ Where search query faster on List<> compared to ConcurrentBag<>

Tags:

c#

linq

I have List collection with 100 million entities in it. When I perform a simple Linq Where() query, it takes approximately 48 ticks (10,000 ticks = 1ms) for a search, whereas putting 100 million entities in a ConcurrentBag and then using the same search query on it takes 58 ticks.

I have repeated the test multiple time and the difference remains pretty much the same. Can someone elaborate why is there a performance difference?

like image 632
Raheel Avatar asked Mar 19 '23 17:03

Raheel


1 Answers

From the spec of ConcurrentBag<T>.GetEnumerator:

The enumeration represents a moment-in-time snapshot of the contents of the bag. It does not reflect any updates to the collection after GetEnumerator was called. The enumerator is safe to use concurrently with reads from and writes to the bag.

Internally, ConcurrentBag is creating a new list every time you enumerate over it, and additional actions.

From ReferenceSource.microsoft.com:

public IEnumerator<T> GetEnumerator()
{
    // Short path if the bag is empty
    if (m_headList == null)
        return new List<T>().GetEnumerator(); // empty list

    bool lockTaken = false;
    try
    {
        FreezeBag(ref lockTaken);
        return ToList().GetEnumerator();
    }
    finally
    {
        UnfreezeBag(lockTaken);
    }
}

private List<T> ToList()
{
    Contract.Assert(Monitor.IsEntered(GlobalListsLock));

    List<T> list = new List<T>();
    ThreadLocalList currentList = m_headList;
    while (currentList != null)
    {
        Node currentNode = currentList.m_head;
        while (currentNode != null)
        {
            list.Add(currentNode.m_value);
            currentNode = currentNode.m_next;
        }
        currentList = currentList.m_nextList;
    }

    return list;
}

Naturally, this must be slower than enumerating over a simple list.

like image 96
Kobi Avatar answered May 03 '23 02:05

Kobi