如何在C#中实现真正的函数管道?

时间:2010-11-13 17:24:37

标签: c# .net ienumerable pipeline

如何使用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#中实现?如果可能的话,请给我一些示例代码。

3 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

我相信缺少一个主要的建筑元素,无论工作是否得到处理。 Pipeline与传统的GoF责任链非常相似,如果您没有GoF书籍,请查看此处:

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

我认为您必须将“T”限制为某个界面,该界面告诉管道是否处理了作业(使用“where”语句)。

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

答案 2 :(得分:0)

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

“简单”方法只是使用Parallel.ForEach配置N“开始” - 当且仅当您可以保证计算是无副作用的时候。

修改:查看评论。