具有永久任务/线程的TPL数据流阻止

时间:2017-06-09 19:29:39

标签: c# .net task-parallel-library scheduled-tasks tpl-dataflow

Stepen Toub在此Channel 9 Video中提到如果项目被推送到其传入队列,则*Block会创建任务。如果计算队列中的所有项目,则任务将被销毁。

如果我使用大量的块来构建一个实际运行的任务数量的网格不明确(如果TaskScheduler是默认值,则活动ThreadPool线程的数量也不是全部清除)。

TPL Dataflow是否提供了一种我可以说的方式:"好的我想要这种具有永久运行任务(线程)的块?

2 个答案:

答案 0 :(得分:1)

TL; DR:没有办法将一个线程专用于一个块,因为它明显与TPL Dataflow的目的相冲突,除非通过实现你自己的TaskScheduler。在尝试提高应用程序性能之前先进行测量。

我刚观看了视频,但却找不到这样的短语:

  如果项目被推送到其传入队列,则

创建任务。如果计算队列中的所有项目,则任务将被销毁。

也许我错过了一些东西,但斯蒂芬所说的只是:[开头]我们有一个共同的Producer-Consumer问题,可以用.Net 4.0堆栈轻松实现,但问题是如果数据耗尽,消费者就会离开循环,永远不会返回。

[之后] Stephen解释说,TPL Dataflow如何解决这个问题,他说ActionBlock 开始一个Task如果它不是&{ #39; t开始了。在该任务中,有代码等待(以async方式)新消息,释放线程,但不会破坏任务。

斯蒂芬在解释链接块中的发送消息时提到了任务,并且他说如果没有数据要发送,发布任务将会消失。它并不意味着与块相对应的任务逐渐消失,它只是关于某些用于发送数据的子任务,而且就是它。

TPL Dataflow中,唯一可以通过调用它的Complete方法或完成任何链接块来阻止不再存在数据的方法。之后消费任务将停止,并且在处理完所有缓冲数据后,该块将结束它的任务。

根据TPL Dataflow的官方github,块内消息处理的所有任务都创建为DenyChildAttach,有时带有PreferFairness标志。因此,我没有理由提供一种机制来将一个线程直接安装到块中,因为如果块没有数据,它将卡住并浪费CPU资源。您可以为块引入一些自定义TaskScheduler,但是现在它并不明显为什么你需要它。

如果您担心某些块可能会比其他块获得更多的CPU时间,那么有一种方法可以利用这种效果。根据{{​​3}},您可以尝试设置official docs属性,在发送一定数量的数据后强制重启任务。不过,在测量实际执行时间之后,这应该是

现在,回到你的话:

  

实际运行的任务数量不明确
  活动的ThreadPool线程数也不清楚

您是如何分析您的申请的?在调试期间,您可以轻松找到MaxMessagesPerTaskall active tasks。如果还不够,您可以使用本机Microsoft工具或专用的分析器(例如all active threads)来分析您的应用程序。此类工具包可以轻松为您提供有关应用中发生的事情的信息。

答案 1 :(得分:0)

The talk与TPL Dataflow库的内部机制有关。作为一种机制,它是一种非常有效的机制,除非您预期的吞吐量约为每秒100,000条消息或更多(在这种情况下,您应该寻找方法来分块工作负载),否则您不必担心任何开销。即使使用非常小的粒度的工作负载,使用一个任务处理所有消息还是处理每个消息都需要一个单独的任务来处理消息之间的差异也应该不明显。 Task是一个通常“重”几百个字节的对象,.NET平台每秒可以创建和回收数百万个这种大小的对象。

如果每个Task需要自己的专用1MB线程才能运行,这将是一个问题,但事实并非如此。通常,这些任务是使用ThreadPool线程执行的,而单个ThreadPool线程每秒可能会执行数百万个短期任务。

我还应该提到TPL数据流也支持异步lambda(具有Task返回类型的lambda),在这种情况下,这些块基本上根本不需要执行任何代码。他们只是等待生成的promise样式任务完成,并且需要异步等待no thread