使用 Parallel.ForEach 或 Task.Run() 异步启动一组任务有什么区别?
版本 1:
List<string> strings = new List<string> { "s1", "s2", "s3" }; Parallel.ForEach(strings, s => { DoSomething(s); });
版本 2:
List<string> strings = new List<string> { "s1", "s2", "s3" }; List<Task> Tasks = new List<Task>(); foreach (var s in strings) { Tasks.Add(Task.Run(() => DoSomething(s))); } await Task.WhenAll(Tasks);
在这种情况下,第二种方法将异步等待任务完成而不是阻塞。
但是,在循环中使用有一个缺点 - Task.RunWith Parallel.ForEach,创建了一个Partitionerwhich 以避免执行不必要的任务。 Task.Run将始终为每个项目创建一个任务(因为您正在执行此操作),但Parallel班级批次工作,因此您创建的任务少于总工作项目。这可以提供明显更好的整体性能,尤其是在循环体每个项目的工作量很小的情况下。
Task.Run
Parallel.ForEach
Partitioner
Parallel
如果是这种情况,您可以通过以下方式组合这两个选项:
await Task.Run(() => Parallel.ForEach(strings, s => { DoSomething(s); }));
请注意,这也可以写成更短的形式:
await Task.Run(() => Parallel.ForEach(strings, DoSomething));