3

我试图更好地理解并行处理的整个概念并设置了测试用例。在玩了测试之后,我发现在 Dataflow ActionBlock(或TransformBlock)中使用 Async 方法调用不会对性能产生积极影响,它只会使代码复杂化。我是否正确假设如果我使用 Dataflow Blocks,其中的代码不必是异步的,Dataflow 会自行使其异步。还是我错过了重点?

4

2 回答 2

8

TPL Dataflow 不支持并发或并行化(尽管您可以获得ActionBlock并行化其处理之类的东西),它是并发或并行代码用于通信数据的东西。除此之外,它是一种消息传递机制——它是共享数据的一种替代方案。共享数据在被多个线程使用时需要昂贵的同步。如果处理得当,消息传递不需要同步,因为需要处理的数据被封装在一条消息中,该消息“发送”到将要处理它的代码。

如果您有特定的设计,您可以使用 TPL 数据流。如果您没有专门实现基于 Actor 的编程、消息传递或非阻塞生产者/消费者场景,那么 TPL 数据流可能会使事情复杂化。

如果您认为您可能想要设计这样的系统,这里有一些很好的资源来了解 TPL 数据流 (TDF),例如 Stephen Toub(Microsoft 并行团队的成员)的视频,以及Dataflow MSDN 页面

更新:

您可以为块设置最大并行度,但将其设置为高于 CPU 或核心数通常会适得其反。假设执行的每个操作都或多或少受 CPU 限制(在运行时以 100% 使用 CPU)。如果操作花费大量时间等待(等待等待句柄,等待消息泵中的消息——这对于操作来说是不正常的,但对于 UI 威胁来说是不正常的——等等),那么一定程度的并行度会超出CPU 的数量可能是有意义的(尽管这很难调整)。当你运行的动作比 CPU多时受 CPU 限制,您真正开始执行操作系统任务。操作系统希望为每个线程(或本例中的每个操作)放弃 CPU 时间,因为它正在“运行”。当没有足够的 CPU 运行时,操作系统开始抢占多任务,循环将 CPU 时间分配给每个活动线程。每次操作系统将 CPU 从一个线程中取出并交给另一个线程时,称为上下文切换。这真的很昂贵(在2000-8000 cpu 周期的范围内)。所以,操作系统真的把所有时间都花在了上下文切换上,而不是运行你的操作。

如果您的操作真的是异步的,那么块的并行度是无关紧要的,因为其他东西正在做并行化。但是,同样的问题出现了,您的异步操作正在未经检查地执行,并且您有可能在您引入的上下文切换程度上压倒操作系统。由于缺乏控制,我会认真考虑不执行异步操作。

于 2012-09-06T15:41:34.897 回答
1

TPL Dataflow 不适合所有类型的并行处理,它也不会让你的代码神奇地更快。

TDF 背后的主要思想是你有块,它们独立地完成它们的工作。这意味着每个块的工作都可以在单独的线程上执行,因此在某些情况下使用 TDF 并行化您的代码可能非常简单。

如果块内的代码使用了一些无法共享的资源,这将特别有用。这样,您可以充分利用该共享资源,因为该块的处理独立于其他块。

一般来说,如果您的代码像管道一样,TDF 最合适:一个项目进入,在阶段 1 处理,然后在阶段 2,......,最后是输出。尽管数据流网络可能比这复杂得多。但是你不应该试图强迫这一点,如果你想做的事情不适合 TDF,你是对的,你只会使你的代码复杂化而没有任何好处。

于 2012-09-06T21:11:06.357 回答