为什么C#Parallel.Invoke很慢?

我这样做:

private static void Main(string[] args) { var dict1 = new Dictionary(); var dict2 = new Dictionary(); DateTime t1 = DateTime.Now; for (int i = 1; i  dict1.Add(i, "Test" + i), () => dict2.Add(i, "Test" + i) ); } TimeSpan t2 = DateTime.Now.Subtract(t1); Console.WriteLine(t2.TotalMilliseconds); Console.ReadLine(); } 

所以做一个100万次循环并将项目添加到两个不同的词典。 问题是需要11秒,这比普通顺序方法(没有任务/线程)多5倍,仅需2秒。 不知道为什么。

像其他人所说或暗示的那样,由于并行化的开销,并行代码并不总是更快。

话虽这么说,你的代码是并行地向2个字典添加一个项目1M次,而你应该并行 添加1M项到2个字典 。 差异很微妙,但最终结果是代码比顺序情况快10%(在我的机器上)。

 Parallel.Invoke(() => FillDictionary(dict1, 1000000), () => FillDictionary(dict2, 1000000)); ... private static void FillDictionary(Dictionary toFill, int itemCount) { for(int i = 0 ; i < itemCount; i++) toFill.Add(i, "test" + i); } 

使用并行调用存在一定的开销,并且可以跨多个内核/ CPU分配工作。 在这种情况下,开销大于有用工作分配的实际收益,因此这就是您看到显着差异的原因。 尝试使用更繁重的操作,您将看到差异。

将其重写为:

 Parallel.Invoke( () => { for (int i = 0; i < 1000000; i++) { dict1.Add(i, "Test" + i); } }, () => { for (int i = 0; i < 1000000; i++) { dict2.Add(i, "Test" + i); } } ); 

这应该快得多,因为两个线程只被初始化一次然后运行完成。 在您的版本中,您每次调用每个lambda表达式1000000次,每次等待两次完成后再继续。

Parallel.Invoke实际上是用于更长时间运行的操作。 否则,设置并行任务并等待它们全部完成的开销只会杀死并行运行任务所获得的任何性能。

Parallel.Invoke意味着“执行所有这些任务并等待它们完成。” 在这种情况下,您只能并行执行两项任务。 因此,并行调用的开销大于并发的潜在收益。

如果你想要做的是在两个不同的词典中添加100000个项目,你应该打破任务之间的工作量,而不是方法。 此方法与您的代码相同,但在我的机器上比您的实现快得多:

 var dict1 = new ConcurrentDictionary(); var dict2 = new ConcurrentDictionary(); Parallel.Invoke(() => { for(int i = 0; i < 500000; i++) { dict1[i] = "Test" +i; dict2[i] ="Test" +i; } }, () => { for(int i = 500000; i < 1000000; i++) { dict1[i] ="Test" +i; dict2[i] = "Test" +i; } });