C# 用任务并行库构建任务处理流水线

C# 用任务并行库构建任务处理流水线,c#,concurrency,task-parallel-library,system.reactive,C#,Concurrency,Task Parallel Library,System.reactive,我来自Objective-C的背景,在那里我会使用Grand Central Dispatch或NSOperations来解决这个问题,这相当简单。不幸的是,当我试图用C#构造这个问题时,我认为我陷入了这种思维方式 我有高级任务,每个任务都有多个部分可以并行执行。这些部件中的每一个都需要在管道中经过几个阶段。我需要构造这个管道,但知道高级任务何时完成,并执行回调 使用GCD,我将创建队列来执行部分,每个队列链接到流程的下一部分。所有这些部分都将根据它们所属的高级任务进行分组,以便在最后触发回调

我来自Objective-C的背景,在那里我会使用Grand Central Dispatch或NSOperations来解决这个问题,这相当简单。不幸的是,当我试图用C#构造这个问题时,我认为我陷入了这种思维方式

我有高级任务,每个任务都有多个部分可以并行执行。这些部件中的每一个都需要在管道中经过几个阶段。我需要构造这个管道,但知道高级任务何时完成,并执行回调

使用GCD,我将创建队列来执行部分,每个队列链接到流程的下一部分。所有这些部分都将根据它们所属的高级任务进行分组,以便在最后触发回调

我正在努力弄清楚这在C#中是如何工作的。我一直在研究任务并行库,但对我使用的东西没有特别的偏好。到目前为止,我遇到的一个问题是,如果您完成了处理,那么完成回调似乎只有在TPL管道中才可能实现,但因为我将有多个不会发生的任务


从总体上看,这个问题最好是如何组织的?我想知道是否最好用Rx编写提供并发性的系统?

我不太明白您所说的由于有多个任务而不能选择完成回调是什么意思。为每个任务构建一个数据流网络意味着分别为它们触发完成

我猜您会希望避免每次重建网络时产生的开销?在这种情况下,也许您可以在末尾添加一个排序的passthrough块:它返回给定的任何输入,还调用您需要的任何回调。因此,对于网络生成的每个输出,都将调用回调。如果您想更进一步,它可以将消息发布到另一个块,然后该块可以并行调用回调

或者,如果管道足够简单,并且您不需要额外的缓冲等等,那么您可以使用普通的TPL任务来完成它?大概是这样的:

public async Task<string> HighLevelTask(string input1, string input2, Action completed) {
    Task<string[]> parts = Task.WhenAll(Part1(input1), Part2(input2));
    string[] results = await parts;
    completed();
    return string.Join(",", results);
}
public async Task<string> Part1(string input) {
    var result1 = await Stage1(input);
    var result2 = await Stage2(result1);
    return result2;
}
public异步任务HighLevelTask(字符串input1,字符串input2,操作已完成){
任务部件=任务.WhenAll(部件1(输入1),部件2(输入2));
字符串[]结果=等待部分;
已完成();
返回字符串。Join(“,”,results);
}
公共异步任务第1部分(字符串输入){
var结果1=等待阶段1(输入);
var result2=等待阶段2(result1);
返回结果2;
}

在我看来,第三方物流数据流是正确的选择。Rx可以做Dataflow可以做的任何事情,但确实擅长事件/时间管理,而Dataflow的语法对于实际数据流(包括管道)来说更干净

数据流没有内置任何类型的每项完成通知,这是正确的。您必须自己添加,例如,在每个项目的末尾粘贴一个
ActionBlock


你会发现我的建议很有用。特别是,我有一些建议,听起来可能正是您所需要的。

TPL足以解决您的问题。我建议您阅读这篇关于MSDN的文章

你说的第三方物流是什么意思?我的理解和你描述的概念非常接近。是的,这就是我一直试图使用的。我发现它非常接近,但缺少对任务进行分组的能力,我看不出如何模拟该功能。这是我失去的关键部分。我需要知道一个小组什么时候结束。管道有多复杂?可以将其建模为一个简单的方法,一个接一个地执行管道中的各个阶段吗?例如,
void executepiline(Part){executestatege1(Part);executestatege2(Part);…}
@svick它可能是,但阶段在某种程度上是可以修改的,我不确定它是否会简化它。通过将工作分解为多个单元,我认为这可能使库能够更有效地对其进行并行处理。我在使用管道之前执行完成回调的方法是添加一个命令,在管道的最后一个阶段标记为已完成时执行这些命令。但由于多批子任务将通过,我无法调用管道头部的
complete
来触发它。不过这是个好主意,我一定会考虑的。虽然看起来我必须手动控制同时执行的任务数量。谢谢,我已经在MSDN上使用了几篇类似的文章,但这篇很好。问题是,我尝试实现完成回调的方式意味着我只能在整个管道完成工作并且不再使用时触发它们。现在,我正在管道中创建一个管道,以便我可以在内部管道上执行此操作(或使用Task.wait方法),因为这将只计算一个高级任务的子任务。