簡體   English   中英

下游的TPL數據流塊如何獲取源生成的數據?

[英]How can a TPL Dataflow block downstream get data produced by a source?

我正在使用TPL Dataflow處理圖像。 我收到處理請求,從流中讀取圖像,應用幾個轉換,然后將生成的圖像寫入另一個流:

Request -> Stream -> Image -> Image ... -> Stream

為此,我使用塊:

BufferBlock<Request>
TransformBlock<Request,Stream>
TransformBlock<Stream,Image>
TransformBlock<Image,Image>
TransformBlock<Image,Image>
...
writerBlock = new ActionBlock<Image>

問題是初始Request是包含創建結果Stream所需的一些數據以及此時我需要的一些其他信息。 我是否必須將原始Request (或其他一些上下文對象) writerBlock到所有其他塊的writerBlock ,如下所示:

TransformBlock<Request,Tuple<Request,Stream>>
TransformBlock<Tuple<Request,Stream>,Tuple<Request,Image>>
TransformBlock<Tuple<Request,Image>,Tuple<Request,Image>>
...

(這很難看),還是有辦法將第一個塊鏈接到最后一個塊(或者,推廣到需要附加數據的塊)?

是的,你幾乎需要做你所描述的,將每個塊中的附加數據傳遞給下一個塊。

但是使用幾個輔助方法,你可以使這更簡單:

public static IPropagatorBlock<TInput, Tuple<TOutput, TInput>>
    CreateExtendedSource<TInput, TOutput>(Func<TInput, TOutput> transform)
{
    return new TransformBlock<TInput, Tuple<TOutput, TInput>>(
        input => Tuple.Create(transform(input), input));
}

public static IPropagatorBlock<Tuple<TInput, TExtension>, Tuple<TOutput, TExtension>>
    CreateExtendedTransform<TInput, TOutput, TExtension>(Func<TInput, TOutput> transform)
{
    return new TransformBlock<Tuple<TInput, TExtension>, Tuple<TOutput, TExtension>>(
        tuple => Tuple.Create(transform(tuple.Item1), tuple.Item2));
}

簽名看起來令人生畏,但實際上並沒有那么糟糕。

此外,您可能希望添加將選項傳遞給創建的塊的重載,或者重載以獲取異步委托的重載。

例如,如果您想使用單獨的塊對數字執行某些操作,同時沿途傳遞原始數字,您可以執行以下操作:

var source = new BufferBlock<int>();
var divided = CreateExtendedSource<int, double>(i => i / 2.0);
var formatted = CreateExtendedTransform<double, string, int>(d => d.ToString("0.0"));
var writer = new ActionBlock<Tuple<string, int>>(tuple => Console.WriteLine(tuple));

source.LinkTo(divided);
divided.LinkTo(formatted);
formatted.LinkTo(writer);

for (int i = 0; i < 10; i++)
    source.Post(i);

如您所見,您的lambda(除了最后一個)只處理“當前”值( intdoublestring ,具體取決於管道的階段),“原始”值(總是int )自動傳遞。 在任何時候,您都可以使用使用普通構造函數創建的塊來訪問這兩個值(例如示例中的最終ActionBlock )。

(那個BufferBlock實際上並不是必需的,但我添加它以更BufferBlock您的設計。)

因為我剛剛開始使用TPL Dataflow,所以我可能會過頭了。 但我相信你可以使用BroadcastBlock作為源和你的第一個目標之間的媒介來實現這一點。

BroadcastBlock可以提供消息給許多目標,所以你用它來提供給您的目標, 同時也為JoinBlock ,在將結果與原始郵件合並結束。

source -> Broadcast ->-----------------------------------------> JoinBlock <source, result>
                    -> Transformation1 -> Transformation 'n'  ->

例如:

var source = new BufferBlock<int>();
var transformation =  new TransformBlock<int, int>(i => i * 100);

var broadCast = new BroadcastBlock<int>(null);
source.LinkTo(broadCast);
broadCast.LinkTo(transformation);

var jb = new JoinBlock<int, int>();
broadCast.LinkTo(jb.Target1);
transformation.LinkTo(jb.Target2);

jb.LinkTo(new ActionBlock<Tuple<int, int>>(
          c => Console.WriteLine("Source:{0}, Target Result: {1}", c.Item1, c.Item2)));

source.Post(1);
source.Post(2);

source.Complete();

收益率...

資料來源:1,目標結果:100

資料來源:2,目標結果:200

我不太確定它在異步環境中的表現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM