上一篇简单的介绍了TDF提供的一些Block,通过对这些Block配置和组合,可以满足很多的数据处理的场景。这一篇将继续介绍与这些Block配置的相关类,和挖掘一些高级功能。

在一些Block的构造函数中,我们常常可以看见需要你输入DataflowBlockOptions 类型或者它的两个派生类型ExecutionDataflowBlockOptions 和 GroupingDataflowBlockOptions。

DataflowBlockOptions

DataflowBlockOptions有五个属性:BoundedCapacity,CancellationToken,MaxMessagesPerTask,NameFormat和TaskScheduler。

用BoundedCapacity来限定容量

这个属性用来限制一个Block中最多可以缓存数据项的数量,大多数Block都支持这个属性,这个值默认是DataflowBlockOptions.Unbounded = -1,也就是说没有限制。开发人员可以制定这个属性设置数量的上限。那后面的新数据将会延迟。比如说用一个BufferBlock连接一个ActionBlock,如果在ActionBlock上面设置了上限,ActionBlock处理的操作速度比较慢,留在ActionBlock中的数据到达了上限,那么余下的数据将留在BufferBlock中,直到ActionBlock中的数据量低于上限。这种情况常常会发生在生产者生产的速度大于消费者速度的时候,导致的问题是内存越来越大,数据操作越来越延迟。我们可以通过一个BufferBlock连接多个ActionBlock来解决这样的问题,也就是负载均衡。一个ActionBlock满了,就会放到另外一个ActionBlock中去了。

用CancellationToken来取消操作

TPL中常用的类型。在Block的构造函数中放入CancellationToken,Block将在它的整个生命周期中全程监控这个对象,只要在这个Block结束运行(调用Complete方法)前,用CancellationToken发送取消请求,该Block将会停止运行,如果Block中还有没有处理的数据,那么将不会再被处理。

用MaxMessagesPerTask控制公平性

每一个Block内部都是异步处理,都是使用TPL的Task。TDF的设计是在保证性能的情况下,尽量使用最少的任务对象来完成数据的操作,这样效率会高一些,一个任务执行完成一个数据以后,任务对象并不会销毁,而是会保留着去处理下一个数据,直到没有数据处理的时候,Block才会回收掉这个任务对象。但是如果数据来自于多个Source,公平性就很难保证。从其他Source来的数据必须要等到早前的那些Source的数据都处理完了才能被处理。这时我们就可以通过MaxMessagesPerTask来控制。这个属性的默认值还是DataflowBlockOptions.Unbounded=-1,表示没有上限。假如这个数值被设置为1的话,那么单个任务只会处理一个数据。这样就会带来极致的公平性,但是将带来更多的任务对象消耗。

用NameFormat来定义Block名称

MSDN上说属性NameFormat用来获取或设置查询块的名称时要使用的格式字符串。

Block的名字Name=string.format(NameFormat, block.GetType ().Name, block.Completion.Id)。所以当我们输入”{0}”的时候,名字就是block.GetType ().Name,如果我们数据的是”{1}”,那么名字就是block.Completion.Id。如果是“{2}”,那么就会抛出异常。

用TaskScheduler来调度Block行为

TaskScheduler是非常重要的属性。同样这个类型来源于TPL。每个Block里面都使用TaskScheduler来调度行为,无论是源Block和目标Block之间的数据传递,还是用户自定义的执行数据方法委托,都是使用的TaskScheduler。如果没有特别设置的话,将使用TaskScheduler.Default(System.Threading.Tasks.ThreadPoolTaskScheduler)来调度。我们可以使用其他的一些继承于TaskScheduler的类型来设置这个调度器,一旦设置了以后,Block中的所有行为都会使用这个调度器来执行。.Net Framework 4中内建了两个Scheduler,一个是默认的ThreadPoolTaskScheduler,另一个是用于UI线程切换的SynchronizationContextTaskScheduler。如果你使用的Block设计到UI的话,那可以使用后者,这样在UI线程切换上面将更加方便。

.Net Framework 4.5 中,还有一个类型被加入到System.Threading.Tasks名称空间下:ConcurrentExclusiveSchedulerPair。这个类是两个TaskScheduler的组合。它提供两个TaskScheduler:ConcurrentScheduler和ExclusiveScheduler;我们可以把这两个TaskScheduler构造进要使用的Block中。他们保证了在没有排他任务的时候(使用ExclusiveScheduler的任务),其他任务(使用ConcurrentScheduler)可以同步进行,当有排他任务在运行的时候,其他任务都不能运行。其实它里面就是一个读写锁。这在多个Block操作共享资源的问题上是一个很方便的解决方案。

 
  1.      public ActionBlock<int> readerAB1;
  2.  
  3. public ActionBlock<int> readerAB2;
  4.  
  5. public ActionBlock<int> readerAB3;
  6.  
  7. public ActionBlock<int> writerAB1;
  8.  
  9. public BroadcastBlock<int> bb = new BroadcastBlock<int>((i) => { return i; });
  10.  
  11. public void Test()
  12. {
  13. ConcurrentExclusiveSchedulerPair pair = new ConcurrentExclusiveSchedulerPair();
  14.  
  15. readerAB1 = new ActionBlock<int>((i) =>
  16. {
  17. Console.WriteLine("ReaderAB1 begin handling." + " Execute Time:" + DateTime.Now);
  18. Thread.Sleep(500);
  19. }
  20. , new ExecutionDataflowBlockOptions() { TaskScheduler = pair.ConcurrentScheduler });
  21.  
  22. readerAB2 = new ActionBlock<int>((i) =>
  23. {
  24. Console.WriteLine("ReaderAB2 begin handling." + " Execute Time:" + DateTime.Now);
  25. Thread.Sleep(500);
  26. }
  27. , new ExecutionDataflowBlockOptions() { TaskScheduler = pair.ConcurrentScheduler });
  28.  
  29. readerAB3 = new ActionBlock<int>((i) =>
  30. {
  31. Console.WriteLine("ReaderAB3 begin handling." + " Execute Time:" + DateTime.Now);
  32. Thread.Sleep(500);
  33. }
  34. , new ExecutionDataflowBlockOptions() { TaskScheduler = pair.ConcurrentScheduler });
  35.  
  36. writerAB1 = new ActionBlock<int>((i) =>
  37. {
  38. Console.ForegroundColor = ConsoleColor.Red;
  39. Console.WriteLine("WriterAB1 begin handling." + " Execute Time:" + DateTime.Now);
  40. Console.ResetColor();
  41. Thread.Sleep(3000);
  42. }
  43. , new ExecutionDataflowBlockOptions() { TaskScheduler = pair.ExclusiveScheduler });
  44.  
  45. bb.LinkTo(readerAB1);
  46. bb.LinkTo(readerAB2);
  47. bb.LinkTo(readerAB3);
  48.  
  49. Task.Run(() =>
  50. {
  51. while (true)
  52. {
  53. bb.Post(1);
  54. Thread.Sleep(1000);
  55. }
  56. });
  57.  
  58. Task.Run(() =>
  59. {
  60. while (true)
  61. {
  62. Thread.Sleep(6000);
  63. writerAB1.Post(1);
  64. }
  65. });
  66.  
  67. }
 

用MaxDegreeOfParallelism来并行处理

通常,Block中处理数据都是单线程的,一次只能处理一个数据,比如说ActionBlock中自定义的代理。使用MaxDegreeOfParallelism可以让你并行处理这些数据。属性的定义是最大的并行处理个数。如果定义成-1的话,那就是没有限制。用户需要在实际情况中选择这个值的大小,并不是越大越好。如果是平行处理的话,还应该考虑是否有共享资源。

TDF中的负载均衡

我们可以使用Block很方便的构成一个生产者消费者的模式来处理数据。当生产者产生数据的速度快于消费者的时候,消费者Block的Buffer中的数据会越来越多,消耗大量的内存,数据处理也会延时。这时,我们可以用一个生产者Block连接多个消费者Block来解决这个问题。由于多个消费者Block一定是并行处理,所以对共享资源的处理一定要做同步处理。

使用BoundedCapacity属性来实现

当连接多个ActionBlock的时候,可以通过设置ActionBlock的BoundedCapacity属性。当第一个满了,就会放到第二个,第二个满了就会放到第三个。

 
  1. public BufferBlock<int> bb = new BufferBlock<int>();
  2.  
  3. public ActionBlock<int> ab1 = new ActionBlock<int>((i) =>
  4. {
  5. Thread.Sleep(1000);
  6. Console.WriteLine("ab1 handle data" + i + " Execute Time:" + DateTime.Now);
  7. }
  8. , new ExecutionDataflowBlockOptions() { BoundedCapacity = 2 });
  9.  
  10. public ActionBlock<int> ab2 = new ActionBlock<int>((i) =>
  11. {
  12. Thread.Sleep(1000);
  13. Console.WriteLine("ab2 handle data" + i + " Execute Time:" + DateTime.Now);
  14. }
  15. , new ExecutionDataflowBlockOptions() { BoundedCapacity = 2 });
  16.  
  17. public ActionBlock<int> ab3 = new ActionBlock<int>((i) =>
  18. {
  19. Thread.Sleep(1000);
  20. Console.WriteLine("ab3 handle data:" + i + " Execute Time:" + DateTime.Now);
  21. }
  22. , new ExecutionDataflowBlockOptions() { BoundedCapacity = 2 });
  23.  
  24. public void Test()
  25. {
  26. bb.LinkTo(ab1);
  27. bb.LinkTo(ab2);
  28. bb.LinkTo(ab3);
  29.  
  30. for (int i = 0; i < 9; i++)
  31. {
  32. bb.Post(i);
  33. }
  34. }
 

测试代码可以从这里下载。

TPL DataFlow初探(二)的更多相关文章

  1. TPL DataFlow初探(一)

    属性TPL Dataflow是微软面向高并发应用而推出的一个类库.借助于异步消息传递与管道,它可以提供比线程池更好的控制,也比手工线程方式具备更好的性能.我们常常可以消息传递,生产-消费模式或Acto ...

  2. 微软面向高并发应用而推出的新程序库——TPL Dataflow

    TPL Dataflow库的几个扩展函数 TPL Dataflow是微软面向高并发应用而推出的新程序库.借助于异步消息传递与管道,它可以提供比线程池更好的控制.本身TPL库在DataflowBlock ...

  3. 一个使用C#的TPL Dataflow Library的例子:分析文本文件中词频

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:一个使用C#的TPL Dataflow Library的例子:分析文本文件中词频.

  4. FluentDataflow - Fluent Style TPL Dataflow

    我的新英文博客文章: FluentDataflow - Fluent Style TPL Dataflow 介绍了本人最新发布的一个开源类库:FluentDataflow--Fluent风格的TPL ...

  5. TPL DataFlow .Net 数据流组件,了解一下

    回顾上文 作为单体程序,依赖的第三方服务虽不多,但是2C的程序还是有不少内容可讲: 作为一个常规互联网系统,无外乎就是接受请求.处理请求,输出响应. 由于业务渐渐增长,数据处理的过程会越来越复杂和冗长 ...

  6. .NET并发编程-TPL Dataflow并行工作流

    本系列学习在.NET中的并发并行编程模式,实战技巧 本小节了解TPL Dataflow并行工作流,在工作中如何利用现成的类库处理数据.旨在通过TDF实现数据流的并行处理. TDF Block 数据流由 ...

  7. JavaScript初探 二 (了解数据)

    JavaScript初探 (二) JavaScript 事件 HTML事件 HTML事件是可以在浏览器或用户做的某些事情 HTML事件的例子: HTML网页完成加载 HTML输入字段被修改 HTML按 ...

  8. RocketMQ初探(二)之RocketMQ3.26版本搭建(含简单Demo测试案例)

    作为一名程序猿,要敢于直面各种现实,脾气要好,心态要棒,纵使Bug虐我千百遍,我待它如初恋,方法也有千万种,一条路不行,换条路走走,方向对了,只要前行,总会上了罗马的道. Apache4.x最新版本既 ...

  9. 游戏服务器菜鸟之C#初探二游戏服务

    经过短时间的折腾,为了解决上述问题,我对游戏进行一些简单的重构,以便能解决当前的瓶颈 添加了缓存服务器进行处理一些及时数据和配置数据,来缓解数据库的压力和IO的压力: 只能说解决当前的暂时性问题,但是 ...

随机推荐

  1. 《Linux内核原理与分析》第九周作业

    课本:第八章 进程的切换和系统的一般执行过程 进行进程调度的时机 Linux内核通过schedule函数实现进程调度,schedule函数在运行队列中找到一个进程,把CPU分配给它 调用schedul ...

  2. 使用miniconda创建python虚拟环境

    安装python指定环境 conda create -n oldboy python=3.6.5 安装环境的同时安装相应的包 conda create -n oldboy python=3.6.5 p ...

  3. PythonStudy——python中如何使输出不换行

    1.在python 3.x版本中,使用print(,end="") 可使输出不换行,  例如:

  4. 创建一个dynamics 365 CRM online plugin (三) - PostOperation

    上两节我们创建了一个 PreOperation的plugin 今天我们创建一个PostOpeartion的plugin和之前的plugin连接起来 当创建contact之后,我们要添加一个task给新 ...

  5. CNN+BLSTM+CTC的验证码识别从训练到部署

    项目地址:https://github.com/kerlomz/captcha_trainer 1. 前言 本项目适用于Python3.6,GPU>=NVIDIA GTX1050Ti,原mast ...

  6. Zuul 跨域

    JS访问会出现跨域问题的解决, 一.对单个接口,处理跨域,只需要在被调用的类或或方法增加注解 CoossOrigin 如下设置 allowCredenticals=true,表示运行Cookie跨域 ...

  7. Windows下好用的git客户端--GitExtentions

    用git: https://git-scm.com/downloads GitExtentions: https://sourceforge.net/projects/gitextensions/ B ...

  8. 命令:jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令

    命令:jstack(查看线程).jmap(查看内存)和jstat(性能分析)命令 这些命令 必须 在 linux jdk bin 路径 下执行 eq: ./jstack 10303 即可  如果想把 ...

  9. ubuntu命令行打开网页

    在Ubuntu下,当需要打开其他格式文件时,比如pdf.jpg.mp3等格式文件,通常做法是进入到文件所在的目录,双击打开,很影响效率.事实上,可以通过命令xdg-open打开这些格式文件,甚至是网页 ...

  10. 廖雪峰Java6 IO编程-2input和output-6classpath资源

    1.从classpath读取文件可以避免不同环境下文件路径不一致的问题. Windows和Linux关于路径的表示不一致 Windows:C:\conf\default.properties Linu ...