【问题标题】:How to parallelize CPU intensive operations in ASP.NET如何在 ASP.NET 中并行化 CPU 密集型操作
【发布时间】:2016-06-29 14:15:37
【问题描述】:

在一个 Asp.NET MVC 应用程序中,我有一个带有要跟踪的活动图的项目。

一个项目没有一个根,而是多个根。 每棵树都可能很复杂且很深,每个节点都依赖于其他节点,例如日期和细粒度的用户权限。

每次对节点进行操作时,我都需要处理所有项目图 因为即使是不同的分支也相互依赖。

该结构以平面形式存储在 SqlServer 数据库中。

为了创建树,我有一个递归函数,它做了很多事情来为每个节点(在当前用户的上下文中)创建一些数据。

例如,我有一个包含 3000 个节点的项目,通过一次调用创建整个图表需要超过 2 秒的时间来处理。

public static List<Nodes> GetProject(...) {
  var list = new List<Nodes>;
  CreateTreeRecursive(...);
  return list;
}

请记住,我有多个根。这让我可以并行化工作并独立处理每个分支。

如果我使用 Task.Run 或 Parallel.ForEach 并行执行,则创建整个图表的时间在 15 到 50 毫秒之间,快 50 倍。

public static List<Nodes> GetProject2(...) {

  var list = new List<Nodes>;

  Parallel.ForEach(...,
    (root) => {
      ...
    });

  return list;
}

坏消息是您不应该在 ASP.NET 中创建线程。

在特定情况下,我没有很多并发用户,但有大约 200 个用户 你不能确定。

另一件事是,一个项目中的根可能很多,最多 100 个,所以很多线程会 被创建。

这个解决方案很简单,但不适用。

有没有办法以简单的方式做到这一点,或者我唯一的选择是将工作分担给一些人 可以跨多个线程并异步等待的外部服务?

如果是这种情况,我会很感激一些建议?

需要明确的是,这是针对项目上的任何用户交互进行的操作。 我无法缓存结果,太不稳定了。我无法在某处排队并最终得到结果。

谢谢

【问题讨论】:

  • 此类问题通常由缓存处理,您的数据源是否可行?您可能无法缓存整棵树,但树的子集可能是可缓存的,无需重新计算。
  • 用户真的需要知道3000个节点的状态吗?如果它们是不同的分支并且它们相互依赖,那么对我来说,它们并不会真的觉得它们是不同的分支。根据您的说法,我们不可能解决您的问题,而且我们最多可以提供广泛的一般性建议,这对于解决问题并没有真正有用,因为我们不知道您知道什么。
  • @ScottChamberlain 是的,我可以缓存分支,但如果编辑频繁,我可能会有非常短暂的缓存条目。每改变一个最小的数据片段就意味着分支的失效。
  • @GeorgeStocker 一个分支只能在开始日期依赖另一个分支。大多数时候用户不需要整张图片,但有时是必要的。
  • 我开始承认(我已经考虑过)我需要缓存一些东西,但我对 ASP:NET 中的并行化问题非常感兴趣,这将是最简单的解决方案。

标签: c# asp.net multithreading parallel-processing async-await


【解决方案1】:

坏消息是您不应该在 ASP.NET 中创建线程。

这不是真的,这个错误的假设阻碍了正确的解决方案。

您可以创建线程。您可能想到的风险是您可能会耗尽线程池的容量。总的来说,这并不容易。

您的线程受 CPU 限制。这意味着您的服务器在池耗尽之前很久就完全超载了。池容量不是您的限制因素。

通过一些假设,我们可以构建一个具体的场景:一个 8 核服务器在 8 个线程上饱和(可以像这里一样运行)。但是如果少于 100 个线程,则不会认为线程池过载。 (实际数字有所不同。100 在各种情况下应该是安全的。)

此外,Parallel.ForEach 使用池线程。它不会创建有意义数量的线程。每个输入项也不占用一个线程。

我觉得这里没什么好担心的。

【讨论】:

  • 这太棒了。那么如果我有 100 个分支 Parallel.ForEach 不会创建 100 个线程?和Task.Run?以及并发用户数的影响是什么?
  • 对于前两个问题,我认为您应该研究一下。已经记录了比我可以在此处添加的更多内容。对于并发用户,这个指标没有意义。让我们谈谈并发请求。假设您的服务器没有在 CPU 上过载,我不明白为什么并行性会在这里产生影响。如果你超载它,所有的赌注都会被取消,但我认为,直觉上很清楚。
  • 由于您的计算是在 50 毫秒后完成的,因此不会有挤占其他用户的风险。
  • @sevenmy 这个问题已经为你解答了吗?
  • 我正在做一些研究和测试。我想我会接受这个答案,因为在我的情况下,该解决方案似乎可以接受,并行化确实提高了性能,并且我仅在图形很大(不常见)、超过 500 个节点以及与缓存相结合以进行读取时使用它-只有场景,所以不应该为每个请求运行。为了便于讨论,您建议使用外部 Windows 服务还是 azure Web 作业作为替代方法?
猜你喜欢
  • 2017-07-25
  • 1970-01-01
  • 1970-01-01
  • 2014-05-12
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 2011-02-26
相关资源
最近更新 更多