我可以制作 TPL DataFlow BatchBlock 单例吗?

Posted

技术标签:

【中文标题】我可以制作 TPL DataFlow BatchBlock 单例吗?【英文标题】:Can I make TPL DataFlow BatchBlock Singleton? 【发布时间】:2018-02-17 13:19:07 【问题描述】:

我能找到的所有示例都表明我必须调用 .Complete() 才能将消息推送到下一个节点,我想知道如果我制作 BatchBlock Singlton,并让它连续接收消息,自动将消息推送到下一个块消息达到批量大小?以这种方式使用 BatchBlock 有什么缺点吗?

【问题讨论】:

不,您不需要调用.Complete(),除非您的消息少于 条消息比批量大小。当您完成您的工作并想要关闭管道时,您在 root 块上调用Complete()。完成将传播到块并使其将任何剩余的消息推送到下一步。 【参考方案1】:

这个问题有点奇怪,因为您不必每次都必须创建一个新的批处理块。您创建 一个 实例并向其发送消息。这就是所有教程和示例所显示的内容。

假设您要读取文件并将内容发送到数据库。您可以使用一个块来读取文件内容,另一个块用于批处理记录,最后一个块一次将数据发送到数据库。这看起来像这样:

var readerBlock=new TransformManyBlock<string,string>(path=>File.ReadLines(path));
var batchBlock=new BatchBlock<string,string>(500);
var dbBlock = new ActionBlock<string[]>(batch=>MyBulkInsertMethod(batch);

var linkOptions = DataflowLinkOptionsPropagateCompletion=true;

readerBlock.LinkTo(batchBlock,linkOptions);
batchBlock.LintTo(dbBlock,linkOptions);

//Start pumping files

forech(var file in Directory.EnumerateFiles(someFolder)

    readerBlock.Post(file);


//Finished pumping, tell the reader 
readerBlock.Complete();
//Wait untile all messages reach the database block and get processed
await dbBlock.Completion;

您必须明确指定当一个块完成时,其链接的块也将完成。这就是PropagateCompletion 所做的。虽然这对于简单的管道来说似乎是一个奇怪的选择,但 TPL 数据流用于创建任意复杂的步骤网格。在这种情况下,您希望能够明确控制要完成的内容。

一旦我们将所有文件泵送到第一个块readerBlock,我们就会告诉我们已经完成了。当该块完成处理时,它将向管道中的 next 块发出信号。

BatchBlock 仅在批处理完成时发送消息,在这种情况下,当它收集 500 行时。 final 批处理可能包含更少的行。如果不调用Complete(),它将永远不会被发送。不过,使用PropagateCompletion,完成将传播到 BatchBlock 并使其将剩余部分发送到下一个块。

最后,我们在最后一个区块上awaitCompletion 任务,确保所有消息都写入数据库

【讨论】:

您实际上并没有在任何地方使用linkOptions。该选项在哪里? 致每个LinkTo 电话

以上是关于我可以制作 TPL DataFlow BatchBlock 单例吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用 TPL-Dataflow 进行聚合和连接(内、外、左……)?

TPL-Dataflow 是不是适用于高并发应用程序?

TPL Dataflow 模块可从单个输入生成多个输出

如何在 TPL/Dataflow 中发出笛卡尔积?

TPL Dataflow,数据块收到第一项时的通知

TPL Dataflow ,完成一个 Block ,重新创建一个 BLock