【问题标题】:Tasks are slower when running in parallel并行运行时任务较慢
【发布时间】:2015-11-17 20:40:14
【问题描述】:

我很难理解为什么这段代码:

// Example #1
foreach (var task in tasks)
{
    task.Start();
    task.Wait();
}

运行速度比:

// Example #2
foreach (var task in tasks)
{
    task.Start();
}

foreach (var task in tasks)
{
    task.Wait();
}

虽然示例 #1 在 1-2 秒内执行所有任务,但示例 #2 需要将近 20 秒才能执行。变量tasks 的类型为Task[]

数组中大约有十几个任务,每个任务需要 500-1000 毫秒来执行。没有 CPU 限制,因为任务只是向服务器发送 HTTP 请求。

这对我来说没有任何意义。

【问题讨论】:

  • 无论有意还是无意,创建这样行为的代码非常容易。因此,这取决于您的任务正在做什么(以及您开始执行多少任务),此时任何阅读本文的人都不知道。在您的情况下,它还取决于您正在访问的 Web 服务器正在做什么,以及它处理并发请求的能力如何,或者如果该服务器再次访问数据库,它可能是世界另一端的数据库实际瓶颈。
  • 如果您向我们展示更多相关代码,会更容易为您提供帮助。
  • 这可能是服务器的原因?也许它一次只处理几个请求?或者,也许所有任务都命中了数据库中的同一张表,并且它们相互干扰。我们需要知道这些任务在做什么(以及服务器对 HTTP 请求做了什么)才能给出有用的答案
  • There is no CPU bound, because tasks just send HTTP requests to server. 那么你不应该首先创建多个线程。您应该让程序中的唯一线程启动所有异步请求,然后处理所有响应。创建一堆只会坐等 IO 的线程会适得其反。
  • @still 您的假设可能是正确的,但也可能是错误的——重要的是要意识到您正在做出假设,并且您应该以某种方式验证这些假设。可以编写一个在处理顺序请求方面非常快的服务器(或 web 应用程序),并且可以编写一个服务器,如果同时遇到太多请求,它会简单地爬到停止状态。数据库也是如此,它可能会以极快的速度处理 1 个单一查询,但如果你一次向它抛出 500 个 SQL 查询,它可能会陷入困境并以指数方式增加所有查询的响应时间。

标签: c# multithreading task


【解决方案1】:

我用@StephenCleary 帮助库解决了我的问题: https://github.com/StephenCleary/AsyncEx

AsyncContext.Run(async () =>
{
    foreach (var task in tasks) task.Start();
    await Task.WhenAll(tasks);
});

现在它的运行速度与 #1 示例一样快,而且在所有请求完成之前也正确等待。

【讨论】:

  • 你能通过简单地将任务存储在一个数组中并使用 await Task.WhenAll(tasks) 来实现相同的结果吗?换句话说,AsyncContext 给你带来了什么?
  • @Sam,在控制台应用程序中,您不能简单地在 Main 方法中调用 await Task.WhenAll(tasks)。据我了解,我之前的代码导致了死锁。您可以在这里找到更多信息:stackoverflow.com/a/9212343/1420356
  • 请看我的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-23
  • 2020-06-21
  • 1970-01-01
  • 2020-01-02
  • 2016-02-28
相关资源
最近更新 更多