- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图了解 WaitAll
和 WhenAll
是如何工作的,但遇到了以下问题。有两种可能的方法可以从方法中获取结果:
return Task.WhenAll(tasks).Result.SelectMany(r=> r);
return tasks.Select(t => t.Result).SelectMany(r => r).ToArray();
如果我理解正确,第二种情况就像在 tasks
上调用 WaitAll
并在之后获取结果。
看起来第二种情况的性能要好得多。我知道 WhenAll
的正确用法是使用 await
关键字,但我仍然想知道为什么这些行的性能差异如此之大。
在分析了系统的流程后,我想我已经想出了如何在一个简单的测试应用程序中对问题建模(测试代码基于 I3arnon 答案):
public static void Test()
{
var tasks = Enumerable.Range(1, 1000).Select(n => Task.Run(() => Compute(n)));
var baseTasks = new Task[100];
var stopwatch = Stopwatch.StartNew();
for (int i = 0; i < 100; i++)
{
baseTasks[i] = Task.Run(() =>
{
tasks.Select(t => t.Result).SelectMany(r => r).ToList();
});
}
Task.WaitAll(baseTasks);
Console.WriteLine("Select - {0}", stopwatch.Elapsed);
baseTasks = new Task[100];
stopwatch.Restart();
for (int i = 0; i < 100; i++)
{
baseTasks[i] = Task.Run(() =>
{
Task.WhenAll(tasks).Result.SelectMany(result => result).ToList();
});
}
Task.WaitAll(baseTasks);
Console.WriteLine("Task.WhenAll - {0}", stopwatch.Elapsed);
}
看起来问题出在从其他任务开始任务(或在 Parallel
循环中)。在那种情况下,WhenAll
会导致程序性能更差。这是为什么?
最佳答案
您正在 Parallel.ForEach
循环中开始任务,您应该避免这种情况。 Paralle.ForEach
的全部要点是在可用的 CPU 内核上并行化许多小而密集的计算,并且开始任务不是密集计算。相反,如果任务池饱和,它会创建一个任务对象并将其存储在队列中,很快就会有 1000 个任务被启动。所以现在 Parallel.ForEach
与任务池竞争计算资源。
在第一个非常慢的循环中,调度似乎不是最优的,使用的 CPU 很少可能是因为 Parallel.ForEach
中的 Task.WhenAll
。如果将 Parallel.ForEach
更改为普通的 for 循环,您将看到加速。
但是,如果您的代码真的像 Compute
函数一样简单,并且在迭代之间没有任何状态转移,您可以摆脱任务并简单地使用 Parallel.ForEach
来最大化性能:
Parallel.For(0, 100, (i, s) =>
{
Enumerable.Range(1, 1000).Select(n => Compute(n)).SelectMany(r => r).ToList();
});
至于为什么 Task.WhenAll
执行得更差你应该意识到这段代码
tasks.Select(t => t.Result).SelectMany(r => r).ToList();
不会并行运行任务。 ToList
基本上将迭代包装在 foreach
循环中,循环主体创建一个任务,然后等待任务完成,因为您检索了 Task。结果
属性。所以循环的每次迭代都会创建一个任务,然后等待它完成。 1000个任务一个接一个执行,处理任务的开销很小。这意味着您不需要执行我在上面建议的任务。
另一方面,代码
Task.WhenAll(tasks).Result.SelectMany(result => result).ToList();
将启动所有任务并尝试并发执行它们,因为任务池无法并行执行 1000 个任务,所以这些任务中的大多数在执行前都已排队。这会产生很大的管理和任务切换开销,这就解释了糟糕的性能。
关于您添加的最后一个问题:如果外部任务的唯一目的是启动内部任务,那么外部任务没有任何用处,但如果外部任务在那里执行内部任务的某种协调tasks 那么它可能有意义(也许你想结合 Task.WhenAny
和 Task.WhenAll
)。没有更多的上下文,很难回答。但是,您的问题似乎与性能有关,开始 100,000 个任务可能会增加相当大的开销。
Parallel.ForEach
如果您想像示例中那样执行 100,000 次独立计算,是一个不错的选择。任务非常适合执行并发事件,这些事件涉及对其他系统的“缓慢”调用,您希望在这些系统中等待并合并结果并处理错误。对于大规模并行性,它们可能不是最佳选择。
关于c# - WhenAll 与 WaitAll 并行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27527253/
我听说在多个线程上使用 waitall 时存在限制(要等待的线程数?)。谁能给详细点? 最佳答案 我认为你所指的限制不是线程的数量;它取决于正在等待的句柄 的数量。来自MSDN page对于 Wait
假设我正在编写一个模拟用户在系统上执行某些操作的软件。我正在使用秒表测量完成此类操作所需的时间。 大多数时候这是非常简单的:模拟按钮的点击,一些服务调用与这个按钮相关联。测量完成此服务调用所需的时间。
当我可以让父任务等待它创建的所有任务时,我不确定创建子任务有什么好处。我运行以下代码,它在两种情况下产生了相同的结果。 public static void Main(string[] args) {
我有这样的情况: var retrievalTasks = new Task[2]; retrievalTasks[0] = GetNodesAsync(); retrievalTasks[1] =
我有少量任务,我想使用 Task.WaitAll 并行运行它们。这是我现在拥有的: type System.Threading.Tasks.Task with static member Wait
我有一个关于 Task.WaitAll 的问题。起初我尝试使用 async/await 来得到这样的东西: private async Task ReadImagesAsync(string HTML
我有一个控制台应用程序,我需要在其中从 4 个不同的站点检索一些数据。我将每个 HTTP 请求放在一个任务中,然后等待它们全部完成。 当我只需要从 2 个站点获取数据时,它就可以正常工作。但后来我需要
是否有可能不使用 WaitHandle.WaitAll(waitHandles) 阻止 winForm,而是设置另一个线程,当从 WaitHandle.WaitAll 获取完成信号时将触发该线程? 最
我想同时运行两个任务,其中一个任务中有一个 Task.Delay()。 即一个连续运行,一个每 15 分钟运行一次。 这是我目前所拥有的: public class ContinousAndAggre
为什么这不是每次都完成?相反,它会抛出一个异常,就像没有捕获到异常一样。此外,异常“索引超出数组范围”对我来说没有意义。 int n = 3; string[] nam
我正在尝试使用此异步代码来测试异步关键字: public async Task AsyncMethod() { var link = "http://www.google.com";
我有两个 ContinueWith 用于一个任务。第一个处理任务成功完成的情况,第二个处理任务失败的情况。然后我等到其中一个完成。示例代码如下: var task = Task.Factory.Sta
我正在使用我的可移植类库异步检索一些 rss 文章,该类库使用 Microsoft.Bcl 库(没有 Task.WhenAll)。每篇文章都有一个 rss 评论的 url,我也需要异步检索它。 下面的
我的目标是从 Amazon Web Services 存储桶下载图像。 我有以下代码功能,可以一次下载多张图片: public static void DownloadFilesFromAWS(str
我的代码中有这样一种情况,我开始执行未知数量的任务并想使用 Task.WaitAll()。 像这样: if (condition) { var task1 = Task.Factory.Sta
我创建了一个 Task 列表,如下所示: public void A() { } public void B() { } public void C() { } public void Ex() {
使用 System.Threading.Tasks.Task.WaitAll() 我可以看到我应该使用此方法的可用参数 可见here但是在 visual studio 中编写时,我可以调用完全没有参数
WaitAll 不工作。我在任务完成之前得到完成。 我有一些群组。每个组都包含项目,我希望每个项目在单独的任务中处理。 static void Main(string[] args) { Li
更新以更清楚地解释事情 我有一个运行多个任务的应用程序。有些是最初创建的,有些可以稍后添加。我需要一个编程结构来等待所有任务完成。一旦所有任务完成,应该运行一些其他代码来清理事情并对其他任务生成的数据
就并行性而言,这些是等价的吗? async Task TestMethod1() { Task t1 = GetInt1(); Task t2 = GetInt2(); awa
我是一名优秀的程序员,十分优秀!