如何在Reactive Extensions中实现并行扇出处理?

时间:2013-10-28 22:57:27

标签: c# parallel-processing system.reactive

我们已经在我们的代码中使用并行扇出工作(使用ParallelEnumerable),该代码当前在12核64G RAM服务器上运行。但我们希望将代码转换为使用Rx,以便我们可以在下游管道上获得更好的灵活性。

当前工作流程:

  1. 我们从数据库中读取了数百万条记录(流式传输)。
  2. 在客户端,我们使用自定义OrderablePartitioner<T>类将数据库记录分组。我们来调用这个类的实例:partioner
  3. 然后我们使用partioner.AsParallel().WithDegreeOfParallelism(5).ForAll(group => ProcessGroupOfRecordsAsync(group));

    注意:这可以被理解为“处理所有组,一次并行5个。”(即并行扇出)

  4. ProcessGroupOfRecordsAsync() - 遍历组中的所有记录并将其转换为数百甚至数千个POCO对象以进行进一步处理(即串行扇出或更好地扩展)。

    根据客户的需求:

  5. 这个POCO对象的新串行流通过手动过程进行评估,排序,排序,转换,过滤,过滤,并且可能在整个管道的其余部分中更加并行和/或串行扇出。

  6. 管道的末尾可能最终将新记录存储到数据库中,在表单中显示POCO对象或以各种图形显示。
  7. 这个过程目前工作正常,但第5点和第6点不像我们想要的那样灵活。我们需要能够交换各种下游工作流程。所以,我们的第一次尝试是使用Func<Tin, Tout>,如此:

    partioner.AsParallel
             .WithDegreeOfParallelism(5)
             .ForAll(group =>ProcessGroupOfRecordsAsync(group, singleRecord =>
                 NextTaskInWorkFlow(singleRecord));
    

    这样做没问题,但是我们越是满足了我们的需求,我们越是意识到我们只是重新实施Rx。

    因此,我们希望在Rx中执行以下操作:

    IObservable<recordGroup> rg = dbContext.QueryRecords(inputArgs)
        .AsParallel().WithDegreeOfParallelism(5)
        .ProcessGroupOfRecordsInParallel();
    
    If (client1)
        rg.AnalizeRecordsForClient1().ShowResults();
    
    if (client2)
        rg.AnalizeRecordsForClient2()
          .AsParallel()
          .WithDegreeOfParallelism(3)
          .MoreProcessingInParallel()
          .DisplayGraph()
          .GetUserFeedBack()
          .Where(data => data.SaveToDatabase)
          .Select(data => data.NewRecords)
          .SaveToDatabase(Table2);
    ...
    using(rg.Subscribe(groupId =>LogToScreen(“Group {0} finished.”, groupId);
    

2 个答案:

答案 0 :(得分:3)

听起来你可能想要调查Dataflows in the Task Parallel Library - 这可能比Rx​​更适合处理第5部分,并且可以扩展以处理整个问题。

一般来说,我不喜欢尝试使用Rx来并行处理CPU绑定任务;它通常不太合适。如果你不太小心,你可能会无意中引入低效率。数据流可以为您提供很好的并行化方式,仅在最有意义的地方进行并行化。

来自MSDN:

  

任务并行库(TPL)提供数据流组件,以帮助提高启用并发的应用程序的健壮性。这些数据流组件统称为TPL数据流库。此数据流模型通过为粗粒度数据流和流水线操作任务提供进程内消息传递来促进基于actor的编程。数据流组件构建在TPL的类型和调度基础结构之上,并与用于异步编程的C#,Visual Basic和F#语言集成。当您有多个必须以异步方式相互通信的操作或希望在数据可用时处理数据时,这些数据流组件非常有用。例如,考虑一个处理来自网络摄像头的图像数据的应用程序。通过使用数据流模型,应用程序可以在图像帧可用时处理它们。如果应用程序增强了图像帧,例如,通过执行光线校正或防红眼,您可以创建数据流组件管道。管道的每个阶段都可能使用更粗粒度的并行功能,例如TPL提供的功能来转换图像。

答案 1 :(得分:1)

卡布!

由于没有人提供任何明确的内容,我会指出可以在GitHub at Rx浏览源代码。快速浏览一下,看起来至少有一些处理(所有这些?)已经在线程池中完成了。所以,除了实现你自己的调度程序(例如Rx TestScheduler)之外,也许不可能明确地控制并行化程度,但它仍然会发生。另请参阅下面的链接,从答案(特别是第一个链接中James提供的答案)来判断,可观察任务按设计排队并进行串行处理 - 但可以为Rx提供多个流来处理。

另请参阅左侧相关且可见的其他问题(默认情况下)。特别是看起来这个Reactive Extensions: Concurrency within the subscriber,可以为您的问题提供一些答案。或者也许是Run methods in Parallel using Reactive

&lt; edit:请注意,如果将对象存储到数据库会出现问题,则Rx流可以将保存操作推送到ConcurrentQueue,这样就可以了单独处理。其他选择是让Rx使用一些时间和项目数的适当组合对项目进行排队,并通过bulk insert将它们推送到数据库。