C # Dictionary Loop Enhanment

I have a dictionary containing about 1 million units. I am constantly obsessed with dictionnary:

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

The execution is a little longer, about 600 ms, I would like to deactivate it. The following are contraindications:

  • MustDoJob values ​​basically remain the same between two DoAllJobs () calls
  • 60-70% MustDoJob == false
  • From time to time, MustDoJob changes to 200,000 pairs.
  • Some p.Value.DoJob () cannot be evaluated at the same time (calling a COM object)
  • Here I don’t need the key part of _dictionnary objet, but I really need it somewhere else.

I wanted to do the following:

  • Parallelized, but I'm not sure if this will be effective thanks to 4.
  • Sorts dictionnary with 1. and 2. (and stop wanting me to find the first MustDoJob == false), but I wonder what 3. will result in

I have not implemented any of the previous ideas, as this can be a lot of work, and I would like to explore other options earlier. So ... any ideas?

+4
source share
6 answers

I would suggest that your business object can raise an event to indicate that it needs to complete the task when MustDoJob becomes true, and you can subscribe to this event and store links to these objects in a simple list, and then process the contents of this list when the DoAllJobs() method is DoAllJobs()

+5
source

My first suggestion was to use only the values ​​from the dictionary:

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

With LINQ, this can be even simpler:

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

This makes it clearer. However, it is unclear what else is actually causing you a problem. How fast do you need to iterate over a dictionary? I expect this to be pretty nippy already ... is there something really wrong with this brute force approach? What effect did it gain 600 ms to iterate over the collection? Is it 600 ms when nothing needs to be done?

One note: you cannot change the contents of a dictionary while it is repeating - be it in this thread or another. This means that you are not adding, deleting, or replacing key / value pairs. This is normal for BusinessObject content to change, but the dictionary relationship between the key and the object cannot change. If you want to minimize the time during which you cannot change the dictionary, you can take a copy of the list of links to objects that require work, and then iterate over them:

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

First try using a profiler. 4 makes me curious - 600 ms may not be so much if the COM object is used most of the time, and then it either parallelizes or lives with it.

First, I would understand with the launch of a profiler that is not designed for a completely wrong problem.

+2
source

Having established that the loop is really a problem (see TomTom answer ), I would save a list of elements on which MustDoJob true - for example, when MustDoJob installed, add it to the list, and when you process and clear the flag, remove it from the list. (This can be done directly using the code that controls the flag, or by creating an event when the flag changes, depending on what you need.) Then you look at the list (which will be only 60-70% of the length), and not the dictionary. The list may contain the object itself or only its key in the dictionary, although it will be more efficient if it contains the object itself, since you avoid searching the dictionary. It depends on how often you queue 200 thousand of them, and how critical the queue time and execution are.

But again: Step 1 - make sure you solve the right problem .

+1
source

Using the dictionary for me implies that the goal is to search for items by key, rather than visiting each item. On the other hand, 600 ms for passing through a million elements are respectable.

Perhaps change your logic so that you can simply select the appropriate elements that satisfy the condition directly from the dictionary.

0
source

Use the KeyValuePairs list instead. This means that you can iterate over superfast by doing

 List<KeyValuePair<string,object>> list = ...; int totalItems = list.Count; for (int x = 0; x < totalItems; x++) { // whatever you plan to do with them, you have access to both KEY and VALUE. } 

I know this post is outdated, but I was looking for a way to iterate through the dictionary without increasing the overhead generated by the Enumerator (GC and all) or, as a rule, a faster way to repeat it.

0
source

Source: https://habr.com/ru/post/1303541/


All Articles