Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Dictionary Loop Enhancment

I have a dictionary with around 1 milions items. I am constantly looping throw the dictionnary :

    public void DoAllJobs()
    {
            foreach (KeyValuePair<uint, BusinessObject> p in _dictionnary)
            {
                if(p.Value.MustDoJob)
                    p.Value.DoJob();
            }
    }

The execution is a bit long, around 600 ms, I would like to deacrese it. Here is the contraints :

  1. MustDoJob values mostly stay the same beetween two calls to DoAllJobs()
  2. 60-70% of the MustDoJob values == false
  3. From time to times MustDoJob change for 200 000 pairs.
  4. Some p.Value.DoJob() can not be computed at the same time (COM object call)
  5. Here, I do not need the key part of the _dictionnary objet but I really do need it somewhere else

I wanted to do the following :

  • Parallelizes but I am not sure is going to be effective due to 4.
  • Sorts the dictionnary since 1. and 2. (and stop want I find the first MustDoJob == false) but I am wondering what 3. would result in

I did not implement any of the previous ideas since it could be a lot of job and I would like to investigate others options before. So...any ideas ?

like image 411
Toto Avatar asked Dec 28 '22 23:12

Toto


2 Answers

What I would suggest is that your business object could raise an event to indicate that it needs to do a job when MustDoJob becomes true and you can subscribe to that event and store references to those objects in a simple list and then process the contents of that list when the DoAllJobs() method is called

like image 124
RobV Avatar answered Jan 12 '23 01:01

RobV


My first suggestion would be to use just the values from the dictionary:

foreach (BusinessObject> value in _dictionnary.Values)
{
    if(value.MustDoJob)
    {
        value.DoJob();
    }
}

With LINQ this could be even easier:

foreach (BusinessObject value in _dictionnary.Values.Where(v => v.MustDoJob))
{
    value.DoJob();
}

That makes it clearer. However, it's not clear what else is actually causing you a problem. How quickly do you need to be able to iterate over the dictionary? I expect it's already pretty nippy... is anything actually wrong with this brute force approach? What's the impact of it taking 600ms to iterate over the collection? Is that 600ms when nothing needs to do any work?

One thing to note: you can't change the contents of the dictionary while you're iterating over it - whether in this thread or another. That means not adding, removing or replacing key/value pairs. It's okay for the contents of a BusinessObject to change, but the dictionary relationship between the key and the object can't change. If you want to minimise the time during which you can't modify the dictionary, you can take a copy of the list of references to objects which need work doing, and then iterate over that:

foreach (BusinessObject value in _dictionnary.Values
                                             .Where(v => v.MustDoJob)
                                             .ToList())
{
    value.DoJob();
}
like image 38
Jon Skeet Avatar answered Jan 12 '23 02:01

Jon Skeet