代码之家  ›  专栏  ›  技术社区  ›  Joel Martinez

并行化考虑

  •  0
  • Joel Martinez  · 技术社区  · 15 年前

    我想了解社区对此的看法。如果我有一个严重绑定了DB/IO的进程,那么使用Task Parallel library并行化单个进程路径有多聪明?

    我举个例子。。。如果我有一堆东西,我需要做以下操作

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

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

    但是我想在本地机器上逻辑地分配任务,这样它就可以像数据库允许的那样快速地处理,而不必等待任何结果。我已经做了一些模拟原型,用Thread.Sleeps替换了db调用(我还尝试了一些使用.SpinWait的变体,速度快了一百万倍),而并行版本比当前的实现要快得多,后者完全是串行的,根本不并行。

    我担心的是给SQL服务器带来太大的压力。。。在我走这条路走得太远之前,有什么需要考虑的吗?

    2 回复  |  直到 15 年前
        1
  •  1
  •   Jim Mischel    15 年前

    另一个选择是创建一个管道,以便第二个组的步骤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,但是概念转换得非常好。

        2
  •  2
  •   Brent Arias    15 年前

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

    我不太理解您对任务的描述,但听起来似乎更多的任务应该直接在数据库中执行(我认为有些细节不可能做到这一点?)