我想了解社区对此的看法。如果我有一个严重依赖 DB/IO 的进程,那么使用任务并行库并行化各个进程路径有多明智?

我将使用一个例子...如果我有一堆物品,并且我需要执行以下操作

  1. 查询数据库以获取项目列表
  2. 执行一些聚合操作,根据动态参数列表对某些项目进行分组。
  3. 对于每个分组结果,根据聚合结果在数据库中查询某些内容。
  4. 对于每个分组结果,进行一些数值计算(3 和 4 将依次发生)。
  5. 对 #3 中计算的结果进行一些插入和更新
  6. 对 #1 中返回的每个项目进行一些插入和更新

从逻辑上讲,我可以在步骤 #3、#5、#6 并行化为任务图,因为其中一项与前一项的结果无关。然而,每一个都将等待数据库(sql server),这很好,我知道我们只能处理 SQL server 允许的范围。

但我想在本地计算机上逻辑地分配任务,以便它的处理速度与数据库允许的速度一样快,而不必等待我们这边的任何事情。我已经做了一些模拟原型,其中我用 Thread.Sleeps 替换了数据库调用(我还尝试了 .SpinWait 的一些变体,速度快了一百万倍),并且并行版本比完全串行的当前实现快得多并且根本不平行。

我担心的是给 SQL 服务器带来太大的压力......在我沿着这条路走得太远之前,我应该考虑什么?

有帮助吗?

解决方案

另一种选择是创建一个管道,以便第二组的步骤 3 与第一组的步骤 4 同时发生。如果您可以在第 5 步中重叠更新,也可以这样做。这样,您就可以进行并发 SQL 访问和处理,但不会给数据库带来过重的负担,因为一次只有两个并发操作。

因此,您按顺序执行步骤 1 和 2(我认为)以获得需要进一步处理的组的集合。然后。你的主线程开始:

for each group
  query the database
  place the results of the query into the calc queue

第二个线程为结果队列提供服务:

while not end of data
  Dequeue result from calc queue
  Do numeric calculations
  place the results of the query into the update queue

第三个线程为更新队列提供服务:

while not end of data
  Dequeue result from update queue
  Update database

System.Collections.Concurrent.BlockingCollection<T> 对于这种事情来说,这是一个非常有效的队列。

这里的好处是,如果 SQL Server 可以处理更多并发事务,您可以通过添加多个计算线程或查询/更新线程来扩展它。

我在日常合并/更新程序中使用与此非常相似的东西,效果非常好。该特定进程不使用 SQL Server,而是使用标准文件 I/O,但这些概念可以很好地转换。

其他提示

如果并行版本比串行版本快得多,我就不会担心 SQL 服务器上的压力...当然,除非与其他一些重要或时间关键的操作相比,您正在执行的任务优先级较低。在数据库服务器上执行。

我不太理解你对任务的描述,但听起来更多的任务应该直接在数据库中执行(我想有些细节使得这不可能?)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top