C#Dictionary Loop Enhancment

我有一本约有一百万件物品的字典。 我不断循环抛出词典:

public void DoAllJobs() { foreach (KeyValuePair p in _dictionnary) { if(p.Value.MustDoJob) p.Value.DoJob(); } } 

执行有点长,大约600毫秒,我想要deacrese它。 这是约束:

  1. MustDoJob值大多数在两次调用DoAllJobs()之间保持不变
  2. MustDoJob值的60-70%== false
  3. MustDoJob有时会改变20万对。
  4. 某些p.Value.DoJob()无法同时计算(COM对象调用)
  5. 在这里,我不需要_dictionnary对象的关键部分,但我确实需要它在其他地方

我想做以下事情:

  • 并行化,但由于4,我不确定是否会有效。
  • 从1和2开始对字典进行排序(并且停止想要找到第一个MustDoJob == false)但是我想知道3.会导致什么

我没有实现任何先前的想法,因为它可能是很多工作,我想先调查其他选项。 所以…任何想法?

我建议你的业务对象可以引发一个事件来指示当MustDoJob变为true时它需要做一个工作,你可以订阅该事件并在简单列表中存储对这些对象的引用,然后处理它的内容调用DoAllJobs()方法时的列表

我的第一个建议是只使用字典中的值:

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

使用LINQ,这可能更容易:

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

这使它更清楚。 但是,目前尚不清楚究竟是什么导致了您的问题。 你需要多快能够迭代字典? 我希望它已经非常糟糕 ……这种蛮力方法有什么问题吗? 它花费600毫秒来迭代收集的影响是什么? 这是600毫秒什么都不需要做任何工作?

有一点需要注意:在迭代它时无法更改字典的内容 – 无论是在此线程还是其他线程中。 这意味着不添加,删除或替换键/值对。 可以更改BusinessObject内容 ,但键和对象之间的字典关系不能更改。 如果要最小化无法修改字典的时间,可以获取对需要工作的对象的引用列表的副本,然后迭代:

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

首先尝试使用分析器。 4让我好奇 – 如果COM对象大部分时间都使用600毫秒,那么它可能不会那么多,然后它要么是并行化的,要么与它一起生活。

我会首先确定 – 通过分析器运行 – 你不会在这里找到完全错误的问题。

确定循环确实是问题(参见TomTom的答案 ),我将维护MustDoJob为真的项目列表 – 例如,当设置MustDoJob时,将其添加到列表中,以及当您处理并清除标志,从列表中删除它。 (这可以通过操作标志的代码直接完成,或者通过在标志更改时引发事件来完成;取决于您需要的内容。)然后循环遍历列表(这只是长度的60-70%) ),而不是字典。 该列表可能包含对象本身或仅包含字典中的键,但如果它保留对象本身就会更有效,因为您可以避免字典查找。 它取决于你排队200k的频率,以及排队与执行的时间关键。

但同样:第1步是确保你正在解决正确的问题 。

对我使用字典意味着意图是通过键来查找项目,而不是访问每个项目。 另一方面,循环通过一百万个项目的600毫秒是可敬的。

也许改变你的逻辑,这样你就可以直接从词典中选择满足条件的相关项目。

请改用KeyValuePairs列表。 这意味着您可以通过执行来超级快速地迭代它

 List> 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. } 

我知道这篇文章很老,但我一直在寻找一种迭代字典的方法,而不会增加创建枚举器的开销(GC和所有),或者通常是一种更快速的迭代方法。