2010-11-13 49 views
5

如何使用C#创建一个真正的函数管道?我有一些想法类似如下,但它不是一个真正的管道如何在C#中实现真正的函数管道?

public static IEnumerable<T> ForEachPipeline<T>(this IEnumerable<T> source, params Func<T, T>[] pipeline) 
{ 
foreach (var element in source) { 
    yield return ExecutePipeline(element, pipeline); 
} 
} 

private static T ExecutePipeline<T>(T element, IEnumerable<Func<T, T>> jobs) 
{ 
var arg = element; 
T result = default(T); 
foreach (var job in jobs) { 
    result = job.Invoke(arg); 
    arg = result; 
} 
return result; 
} 

在上面的代码中IEnumerable<T>每个元素将能够进入前一个元素执行完所有功能后,才管线(即退出但根据定义如果element1完成执行func1并开始执行func2,那时element2应该开始执行func1等等,从而维持流水线中数据的连续流动。

这种场景是否可以在C#中实现?如果可能的话,请给我一些示例代码。

+0

除非引入线程,否则只有一个执行上下文(单线程的替代方法只是在每个步骤构建的非延迟结果)。使用线程,每个阶段只是一个FIFO队列,通过“泵”传递消息。线程(实际上,并发)也大大增加了复杂性,可能会看到.NET4“并行”方法。 – 2010-11-13 17:28:04

+0

我在介绍线程时没有问题,无论如何我需要做的工作..请分享一些想法 – 2010-11-13 17:30:53

+0

PLINQ不会解决这个问题吗? http://msdn.microsoft.com/en-us/library/dd460688.aspx – bzlm 2010-11-13 17:34:33

回答

0

从评论:只有一个执行上下文,除非线程被引入(单线程的替代方法只是在每个步骤构建非惰性结果)。使用线程,每个阶段只是一个FIFO队列,通过“泵”传递消息。线程(实际上,并发)也大大增加了复杂性,可能会看到.NET4“并行”方法。

一个“简单”的方法就是使用Parallel.ForEach来配置N“开始” - 当且仅当您可以保证计算没有副作用时。

编辑:查看评论(s)。

+0

这是一个想法,但在这种模式中,我如何确保Enumerable的结果与源Enumerable的顺序相同? – 2010-11-13 17:47:25

+1

@AnindyaChatterjee:不是使用'Parallel.ForEach',而是通过'ParallelEnumerable'扩展方法使用Parallel Linq(PLINQ),它包括['AsOrdered'](http://msdn.microsoft.com/en-us/library /dd642142.aspx)运算符来维护您的输入排序。 – Richard 2010-11-13 18:19:22

0

此行为比真正的管道更高效。如果操作可以并行运行,则流水线只有意义,但所有这些作业共享一个CPU线程,因此即使流水线化也必须按顺序执行。

如果您了解不会有任何性能改进,并且仍然想要发表评论,我会展示如何,但我首先要确保您知道您要求的内容。

+0

你为什么认为真正的管道不会增加吞吐量?无论如何,我非常有兴趣看到一个真正的管道实现,我会检查自己的吞吐量。 – 2010-11-13 17:34:33

0

我相信一个主要的建筑元素缺失,无论是否处理作业。管道是非常相似的责任的传统GoF的链条,如果你没有GoF的书周围的人到这里看看:

http://www.dofactory.com/Patterns/PatternChain.aspx#_self1

我认为你必须限制你的“T”的一些接口,告诉管道是否处理了作业(使用“where”语句)。

另外,看看PLINQ框架。我知道这不是你想要的(那里的意图是同时执行几个工作),但它可能会给你一些好的想法。

+0

如果我应用这个模式,它将和我上面提到的代码一样,不管怎样它都不是真正的管道。 – 2010-11-13 17:51:09