2

I'm looking for a data structure that is able to handle concurrency well (as removal & add from multiple threads will happen), and that allows me to map quickly (O(1)) from a hashed key to the corresponding object.

I also have to be able to retrieve X elements at random from this data structure.

I started with a Set, but oddly enough there is no ConcurrentSet implementation and I want to retrieve the reference to my object, as I want to do things with it.

I'm currently having a ConcurrentDictionary that maps an int (the hashed value) to the object. This seems to work fine for the first requirements, but this is not convenient at all for picking elements at random. I've thought about converting the values to an array and picking at random from this, but I don't think this would fit in term of complexity and memory.

Is there a way to do this ? Or another approach to this problem that would allow me to have good performances to map objects concurrently and pick some at random ?

Cholesterol
  • 177
  • 2
  • 10
  • 1
    Have you tried ConcurrentBag ?? – T.Aoukar May 28 '18 at 16:38
  • I have to be able to remove element from the datastructure – Cholesterol May 28 '18 at 16:40
  • 1
    How about generating a random number (based on the number of items in you dictionary) and using ElementAt to retrieve? – Kevin May 28 '18 at 16:44
  • 3
    Pretty sure you can remove an element from it using `TryTake` method – T.Aoukar May 28 '18 at 16:44
  • Also give a Look at F# Concurrency https://fsharpforfunandprofit.com/posts/concurrency-intro/ – Tony May 28 '18 at 17:00
  • Just a fyi, if you do not need the `ISet` specific methods like `IsSupersetOf(` and you only need the `Contains(` check you can easily turn a ConcurrentDictionary in to a ConcurrentSet, just decare the dictionary `ConcurrentDictionary` then any place you call `Add` you just use `null` as the value and anyplace you call `Contains` you call `ContainsKey` – Scott Chamberlain May 28 '18 at 17:21
  • Do you want to actually remove the randomly selected items at the time that they are randomly selected? Or is item removal done at a different time? – Matthew Watson May 28 '18 at 17:37

1 Answers1

2

Iterating over the ConcurrentDictionary is lock-free and relatively cheap. I would suggest picking a bunch of random numbers from 0 to dict.Count - 1, then iterating with foreach or LINQ and retrieving items at these indexes.

But the whole solution depends on the use case. If you rarely update the dictionary, but often read it, you may consider copy-on-write semantics which allows operating on a "snapshot" of data: https://github.com/apache/ignite/blob/master/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs

Pavel Tupitsyn
  • 8,393
  • 3
  • 22
  • 44
  • 2
    As an alternate solution, [ImmutableDictionary](https://msdn.microsoft.com/en-us/library/dn467181(v=vs.111).aspx) built in to .net has copy on write semantics too – Scott Chamberlain May 28 '18 at 17:16