在 C# 中,DataflowBlock 是 TPL Dataflow 库中的核心概念,代表数据流网络中的一个处理节点。TPL Dataflow(Task Parallel Library Dataflow)是 .NET 中用于构建高性能、异步数据处理管道的库,特别适用于生产者-消费者模式、并行任务协调和数据流驱动型应用。
1.DataflowBlock 的定位
DataflowBlock 是 TPL Dataflow 中所有数据流块的基类(如 BufferBlock, ActionBlock, TransformBlock<TInput, TOutput> 等)。每个块代表一个数据处理单元,可以:
- 接收数据(作为生产者)
- 处理数据(执行转换、过滤等操作)
- 传递数据(作为消费者或中间节点)
数据流块通过链接(LinkTo)形成管道或网络,实现数据流的自动传递和处理。
2. 核心功能
(1) 数据传递
-
输入与输出:块可以有输入缓冲区(接收数据)和输出缓冲区(发送处理结果)。
-
链接传播:通过 LinkTo 方法将块链接到下游块,数据自动传递。
(2) 背压支持(Backpressure)
当块的缓冲区已满时,上游块会自动暂停发送数据,避免内存溢出。
通过 BoundedCapacity 配置缓冲区大小。
(3) 异步处理
支持 async/await,块可以异步处理数据(如 ActionBlock 的异步委托)。
使用 SendAsync 方法实现非阻塞的异步数据发送。
(4) 完成与错误处理
- 标记完成:调用 Complete() 通知块不再接收新数据。
- 等待完成:通过 Completion 属性(Task)等待块处理完所有数据。
- 错误传播:若块处理中发生异常,错误会传播到 Completion 任务。
3. 常见内置 DataflowBlock 类型
块类型 | 作用 |
---|---|
BufferBlock | 简单的缓冲区,存储数据并传递给下游。 |
ActionBlock | 对每个输入数据执行同步或异步操作(无输出)。 |
TransformBlock<T, U> | 对输入数据执行转换,生成输出数据。 |
TransformManyBlock<T, U> | 将单个输入映射到多个输出。 |
BroadcastBlock | 将数据广播给所有链接的下游块(每个数据只保留最新值)。 |
BatchBlock | 将多个输入数据打包成批次(如每10个数据组成一个数组输出)。 |
JoinBlock<T1, T2> | 合并多个输入源的数据(如等待两个类型的数据配对后输出元组)。 |
4. 基本用法示例
生产者-消费者模型
using System.Threading.Tasks.Dataflow;
// 创建一个缓冲区块(生产者)
var bufferBlock = new BufferBlock<int>();
// 创建一个处理块(消费者)
var actionBlock = new ActionBlock<int>(x => {
Console.WriteLine($"Processing {x}");
});
// 链接两个块:bufferBlock -> actionBlock
bufferBlock.LinkTo(actionBlock);
// 生产者发送数据
bufferBlock.Post(1);
bufferBlock.Post(2);
bufferBlock.Post(3);
// 标记缓冲区完成,等待消费者处理
bufferBlock.Complete();
await actionBlock.Completion;
- 高级配置
(1) 执行选项
通过 ExecutionDataflowBlockOptions 控制并行度和任务调度:
var options = new ExecutionDataflowBlockOptions {
MaxDegreeOfParallelism = 4, // 最大并行度
BoundedCapacity = 100, // 缓冲区容量
TaskScheduler = TaskScheduler.Default
};
var actionBlock = new ActionBlock<int>(async x => {
await Task.Delay(100);
Console.WriteLine(x);
}, options);
(2) 数据过滤
使用 LinkTo 的谓词参数过滤数据:
bufferBlock.LinkTo(actionBlock1, x => x % 2 == 0); // 仅传递偶数
bufferBlock.LinkTo(actionBlock2, x => x % 2 != 0); // 传递奇数
- 使用场景
流水线处理:如图像处理(解码 → 调整大小 → 编码)。
事件聚合:从多个源收集数据后批量处理。
任务协调:控制并行任务的执行顺序和资源竞争。
实时数据处理:日志分析、消息队列消费等。
- 注意事项
线程安全:DataflowBlock 是线程安全的,允许多线程调用 Post 或 SendAsync。
资源释放:及时调用 Complete() 并等待 Completion,避免资源泄漏。
错误处理:始终通过 Completion 捕获异常:
try {
await block.Completion;
} catch (Exception ex) {
Console.WriteLine($"Block failed: {ex.Message}");
}
总结
DataflowBlock 提供了一种声明式、高并发的数据流编程模型,适用于复杂的数据处理场景。通过组合不同的块,可以轻松构建高效、可扩展的数据处理管道,同时通过背压机制和异步支持,避免资源耗尽问题。