数据流 Block(Dataflow Block)是.NET 4.5 中新的高性能并行处理程序库的支撑核心。尽管其中提供了很多现成的功能,但有时候仍然需要自定义的 block。Zlatko Michailov 完成了一个文档,其中列出了定制的过程,还指出可能会遇到的诸多陷阱。完整的指南《实现自定义的任务并行库(TPL)数据流Block》可以在 Parallel Programming with .NET 中找到,我们这里会提供一些重点。
Zlatko 提醒:在动手之前,你要先考虑是不是就是把现有的 ITargetBlock 和 ISourceBlock 放在一起。如果是的话,Encapsulate 函数会给你创建一个新的 IPropagatorBlock 。该函数会完成大部分的样板代码,但是你仍然要显式声明如何把消息从目标传递到来源 block。
要想有更多控制,你可以显式实现 ITargetBlock 和 ISourceBlock 。与大多数抽象接口不同,不是所有的方法都要在实现类的公共接口上暴露出去。有些方法,比如 LinkTo 和 Complete 是要被通用代码调用的,而其他像 OfferMessage 这样的方法,只能被其他 block 通过抽象接口调用。指南中的 5.1 节针对每个方法推荐了可见性规则。
接下来 Zlatko 展示了两个详细的例子。第一个是同步过滤 block,第二个是同步变型 block。尽管其中有很多样板代码,但的确演示了很多 TPL 数据流的内部运作机制。
Zlatko 谈到异步 block 时,真正难以对付的代码出现了。你从一开始就要考虑锁层次这样的东西。Zlatko 推荐内建 block 使用的方法,包括一个外发(outgoing)锁,一个进入(incoming)锁和一个值锁(value lock)。
标记一个 block 为完成,这看起来很简单,只要在调用 Complete 或 Fault 时设置 Completion 属性即可。可一旦开始使用异步 block,即使是这样的操作也会很麻烦。比如,实际完成属性设置时,必须保证没有拥有某个锁,因此这可能出发其他的同步代码。
另一个考虑在于:是以贪婪还是非贪婪的方式消费消息。如果使用非贪婪 block,那就得采用额外步骤,避免与监听同一个来源的其他目标冲突。
最后,Zlatko 谈到了提供消息和链接目标。不过这就简单了,因为所有的操作本意都采取同步方式。
如果想了解更多信息,请查看 DevLaps 上的 TPL 数据流网站。
评论