2

At first my thought was like "this is an hash-based data type, then it is unsorted".

Then since I was about to use it I examined the matter in depth and found out that this class implements IEnumerable and also this post confirmed that it is possible to iterate over this kind of data.

So, my question is: if I use foreach over a ConcurrentDictionary which is the order I read the elements in?

Then, as a second question, I'd like to know if the sorting methods inherited by its interfaces are of any kind of use. If I call a sorting method over a ConcurrentDictionary the new order will persist (for example for an incoming foreach)?.

Hope I've made myself clear

Community
  • 1
  • 1
Leggy7
  • 483
  • 9
  • 23

3 Answers3

6

The current implementation makes no promises whatsoever regarding the order of the elements. A future implementation can easily change the order by which the elements are enumerated.

As such, your code should not depend on that order.

From the Dictionary<TKey, TValue> msdn docs:

The order in which the items are returned is undefined.

(I couldn't find any reference regarding the ConcurrentDictionary, but the same principle applies.)

When you refer to "the sorting methods inherited by its interfaces", do you mean LINQ extensions? Like OrderBy? If so, these extensions are purely functional and always return a new collection. So, to answer your question "the new order will persist?": no, it won't. You can however use it like this:

foreach(KeyValuePair<T1, T2> kv in dictionary.OrderBy(...))
{

}
dcastro
  • 66,540
  • 21
  • 145
  • 155
  • Yes, I was referring to the LINQ extension and oh yeah, darn, I read too fast that thing and didnt care about the return type. Thank you for your explaination. So I can state that iterating over a ConcurrentDictionary in a specific order is possible only relying on an ordered data set which points to the keys. – Leggy7 Nov 29 '13 at 18:07
1

if I use foreach over a ConcurrentDictionary which is the order I read the elements in?

You get them in the order of buckets they belong to, and if a bucket contains multiple items, the items are in the order in which they've been added. But as others have said, this is an implementation detail you shouldn't rely on.

I'd like to know if the sorting methods inherited by its interfaces are of any kind of use. If I call a sorting method over a ConcurrentDictionary the new order will persist (for example for an incoming foreach)?.

I assume you're refering to the OrderBy() extension method on the IEnumnerable<KeyValuePair<TKey, TValue>> interface. No nothing will persist. This method returns another IEnumnerable<KeyValuePair<TKey, TValue>>. The dictionary remains as it is.

Reda
  • 2,289
  • 17
  • 19
0

Sounds like you might be asking for trouble if you aren't particularly careful. As was mentioned by dcastro order of elements is not ensured. A more troublesome issue is that a ConcurrentDictionary can be changed at any time by other threads. This means that even if order was ensured there is no reason why new items being added while you iterate wouldn't be missed. Unless you know you can prevent other threads from changing the dictionary it's probably not a good idea to iterate over it.

Dweeberly
  • 4,668
  • 2
  • 22
  • 41
  • 1
    `ConcurrentDictionary`'s implementation of `GetEnumerator` return a snapshot of the dictionary. Kinda like a copy of it. So it's safe to enumerate all collections under the `System.Collections.Concurrent` namespace. – dcastro Nov 29 '13 at 16:00
  • 1
    Just to correct my previous comment: after looking at the source code, the implementation does not return a snapshot of the dictionary - "The contents exposed through the enumerator may contain modifications made to the dictionary after GetEnumerator was called". But it still is safe to enumerate on: "The enumerator is safe to use concurrently with reads from and writes to the stack" Source code: http://goo.gl/sU7d8f – dcastro Nov 29 '13 at 16:06
  • It is save to enumerator through, I just wanted to point out that being able to do it might not be the same as wanting to do it. Non-parallel enumeration allows you to move through a collection and know you have accessed each item. Parallel enumeration has the problem that items are changing at the same time you are enumerating so when you get to the end you don't know that you've processed each element or even that any of the elements you've processed are still in the collection. – Dweeberly Nov 29 '13 at 21:09
  • Can you describe a situation where you'd need a "real time" enumerator? I've used these concurrent collections dozens of times, and enumerating on a snapshot was never a problem. I actually think this is a very natural way of implementing this - I would have done the same. – dcastro Nov 29 '13 at 21:35
  • Actually, what's the point of making sure that you haven't missed an item by the time you end enumerating the collection? If an item is added 1 nano second later, you'll miss it anyway. – dcastro Nov 29 '13 at 21:38
  • I'm not trying to be argumentative, I was just trying to point out that enumerating a ConcurrentDictionary (rather than 'by key' access) might point a design issue and that expectations built using non-parallel collections might not hold in parallel coding. – Dweeberly Nov 29 '13 at 21:52
  • I get your point, I was just wondering why you described this behaviour as "troublesome", because I think It's actually desirable. – dcastro Nov 29 '13 at 22:00