2010-11-13 68 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