transformblock 是 tpl dataflow 中需显式配置的异步数据处理单元,必须传入 func 并设置 executiondataflowblockoptions(如 maxdegreeofparallelism、boundedcapacity),且上游须调用 complete() 才能触发数据流动。

TransformBlock 不是通用转换函数,它是 TPL Dataflow 中的异步数据处理单元,必须配合 ExecutionDataflowBlockOptions 显式配置才能发挥价值。默认单线程、无界缓冲、同步执行 —— 这种用法和直接调用方法没区别,还多一层调度开销。
TransformBlock 构造时必须传 Func>
同步委托(比如 Func<string int></string>)会让 TransformBlock 在线程池线程上阻塞执行,吞掉并行能力,还可能拖垮整个 dataflow 网络。异步转换才是它设计的本意:
- 必须用
Func<tinput task>></tinput>,哪怕逻辑本身同步,也建议包一层Task.FromResult(...) - 若误传
Action<t></t>或普通同步Func,编译器不会报错,但运行时行为退化为串行,且无法被await或参与取消传播 - 常见错误现象:
TransformBlock<string int>(s => s.Length)</string>看似能跑通,但所有输入都在同一个线程上顺序执行,MaxDegreeOfParallelism形同虚设
不设 ExecutionDataflowBlockOptions 就等于没用 TransformBlock
TransformBlock 的默认选项是保守的:最大并行度为 1、缓冲无界、不响应取消。你不主动干预,它就只是个带队列的普通方法包装器:
-
MaxDegreeOfParallelism = 1:即使你喂入 1000 个任务,也只用一个线程逐个处理 -
BoundedCapacity = int.MaxValue:上游疯狂投递,下游卡住时内存持续上涨,直到OutOfMemoryException - 正确做法是显式传入选项对象,例如:
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4, BoundedCapacity = 64, CancellationToken = token } - 注意:
DataflowBlockOptions.Unbounded不是“自动伸缩”,而是放弃反压控制,生产环境慎用
LinkTo 之后记得调用 Complete() 才会真正触发数据流动
TransformBlock 是被动拉取模型:它不会主动从上游读数据,除非你明确告诉它“上游结束了”——也就是调用 Complete()。否则即使你 Post 了数据,它也可能一直不处理:
- 只调用
source.Post(item)不够,必须在所有Post完成后调用source.Complete() -
Complete()触发的是“完成信号”,不是“立即执行”。下游块需自行监听Completion任务来感知结束 - 常见错误现象:程序看似卡住、日志没输出、
outputBlock.Count始终为 0 —— 很大概率是忘了source.Complete() - 如果上游是流式来源(如文件读取循环),应改用
SendAsync+Completion.ContinueWith链式处理,避免手动管理完成时机
最易被忽略的一点:多个 TransformBlock 链式调用时,每个块的 Completion 都要单独 await,不能只等最后一个;中间任一块出错未处理,后续块就会永远挂起。











