并发系列64章(TPL 数据流)第七章
前言
什么是TPL?全称:transmission control protocol
传输层对应于OSI七层参考模型的传输层,它提供两种端到端的通信服务。
然后思维方式回到为什么有这个TPL 数据流上。
TPL 数据流库向具有高吞吐量和低滞后时间的占用大量 CPU 和 I/O 操作的应用程序的并行化和消息传递提供了基础。 它还能显式控制缓存数据的方式以及在系统中移动的方式。
为了更好地了解数据流编程模型,请考虑一个以异步方式从磁盘加载图像并创建复合图像的应用程序。
传统编程模型通常需要使用回调和同步对象(例如锁)来协调任务和访问共享数据。
通过使用数据流编程模型,您可以从磁盘读取时创建处理图像的数据流对象。
在数据流模型下,您可以声明当数据可用时的处理方式,以及数据之间的所有依赖项。 由于运行时管理数据之间的依赖项,因此通常可以避免这种要求来同步访问共享数据。
此外,因为运行时计划基于数据的异步到达,所以数据流可以通过有效管理基础线程提高响应能力和吞吐量。
分析一下,这段话。
TPL 数据流库向具有高吞吐量和低滞后时间的占用大量 CPU 和 I/O 操作的应用程序的并行化和消息传递提供了基础。
解决一个问题就是:
高吞吐量和低滞后时间的占用大量 CPU 和 I/O 操作的应用程序。
如何解决的:
应用程序的并行化和消息传递提供了基础。通过并行解决的。
例子:
异步方式从磁盘加载图像并创建复合图像的应用程序
遇到的问题:
协调任务和访问共享数据 需要 回调和同步。
就是说共享数据的时候,需要同步。
总结问题:共享数据代价大。
如果解决的:
由于运行时管理数据之间的依赖项,因此通常可以避免这种要求来同步访问共享数据。
总结:解决了依赖,那么不需要同步了。
综上所述:TPL 数据流库的作用在于解决数据之间的依赖,避免同步访问共享数据。
正文
链接数据流块
var multiplyBlock = new TransformBlock<int, int>(item=>item*2);
var subtractBlock = new TransformBlock<int, int>(item=> { Console.WriteLine(item); return item - 2; });
multiplyBlock.LinkTo(subtractBlock);
multiplyBlock.Post(10);
Console.ReadKey();
打印出来就是20了。
传递出错信息
需要处理数据流网格中发生的错误
如果数据流块的委托抛出异常,这个块就是故障块。一但数据流进入了故障状态,就会删除所有数据(停止接收新的数据)。
什么意思呢?
static async void datalfow()
{
var multiplyBlock = new TransformBlock<int, int>(item =>
{
if (item == 1)
{
throw new InvalidOperationException("not good");
}
return item * 2;
}
);
var subtractBlock = new TransformBlock<int, int>(item => { Console.WriteLine(item); return item - 2; });
multiplyBlock.LinkTo(subtractBlock, new DataflowLinkOptions { PropagateCompletion = true});
try
{
multiplyBlock.Post(10);
multiplyBlock.Post(1);
multiplyBlock.Post(20);
await subtractBlock.Completion;
}
catch(AggregateException e)
{
Console.WriteLine(e);
}
}
结果是:
有没有发现multiplyBlock.Post(20);,没有运行?
因为一但一个有错误,那么就会终止,并销毁数据。
这里和上面不同的是,new DataflowLinkOptions { PropagateCompletion = true}。
多个这个东西,那么这个有啥用呢?
因为我们链接块的时候,这个库不会帮助我们传递块运行的状态,如果不传递的话,下一个块是不晓得上一个块到底啥情况,这样不利于我们捕获异常。
而这种传递做法,我们只要在最后的处理模块,统一处理错误就可以。
断开链接
这个我从来就没有遇到过。是这样子的,适用一种这样的场景。
比如说有一个数据块需要动态替换,需要断开现有的模块然后接上新的数据块。
static async void datalfow()
{
var multiplyBlock = new TransformBlock<int, int>(item =>
{
if (item == 1)
{
throw new InvalidOperationException("not good");
}
Console.WriteLine("item:" + item);
return item * 2;
}
);
var subtractBlock = new TransformBlock<int, int>(item => { Console.WriteLine(item-2); return item - 2; });
var appendBlock = new TransformBlock<int, int>(item => { Console.WriteLine(item+2); return item + 2; });
var link=multiplyBlock.LinkTo(subtractBlock, new DataflowLinkOptions { PropagateCompletion = true});
try
{
for (int i = 0; i < 20; i++)
{
multiplyBlock.Post(2);
if (i==10)
{
await Task.Delay(1000);
link.Dispose();
multiplyBlock.LinkTo(appendBlock, new DataflowLinkOptions { PropagateCompletion = true });
}
}
await subtractBlock.Completion;
}
catch(AggregateException e)
{
Console.WriteLine(e);
}
}
结果是:
值得注意的是,我这里了一个:
await Task.Delay(1000);
这是模拟动态运行的时候,因为当我post结束的时候,数据块链接还没开始传递。
注:
除非保证链接是空闲的情况下,否则在断开数据块的链接时候会出现竞争。
竞争的是先断开还是先传递。
但是这种竞争是安全的,他会保证要不断开,要不传递带下一个数据块。
限制流量
前面我们都是线性链接,就是一条路走到黑。但是呢,有时候出现分叉的时候,那么该如何均衡呢?
之所以考虑均衡,是因为比如传递到下一个数据块的时候,是会有缓存的。如果有条分叉,一条分叉无限去缓存,那另外一条可能吃不上饭了。
static async void datalfow()
{
var multiplyBlock = new TransformBlock<int, int>(item =>
{
if (item == 1)
{
throw new InvalidOperationException("not good");
}
Console.WriteLine("item:" + item);
return item * 2;
}
);
var subtractBlock = new TransformBlock<int, int>(item => { Console.WriteLine(item-2); return item - 2; });
var appendBlock = new TransformBlock<int, int>(item => { Console.WriteLine(item+2); return item + 2; });
multiplyBlock.LinkTo(subtractBlock, new DataflowLinkOptions { PropagateCompletion = true});
multiplyBlock.LinkTo(appendBlock, new DataflowLinkOptions { PropagateCompletion = true });
try
{
for (int i = 0; i < 100; i++)
{
multiplyBlock.Post(2);
}
await subtractBlock.Completion;
}
catch(AggregateException e)
{
Console.WriteLine(e);
}
}
这种就属于没吃上饭的情况。
static async void datalfow()
{
var multiplyBlock = new TransformBlock<int, int>(item =>
{
if (item == 1)
{
throw new InvalidOperationException("not good");
}
Console.WriteLine("item:" + item);
return item * 2;
}
);
var options = new DataflowBlockOptions {BoundedCapacity=1 };
var subtractBlock = new TransformBlock<int, int>(item => {
return item - 2;
}, options);
var appendBlock = new TransformBlock<int, int>(item => { Console.WriteLine(item+2); return item + 2; }, options);
multiplyBlock.LinkTo(subtractBlock, new DataflowLinkOptions { PropagateCompletion = true});
multiplyBlock.LinkTo(appendBlock, new DataflowLinkOptions { PropagateCompletion = true });
try
{
for (int i = 0; i < 100; i++)
{
multiplyBlock.Post(2);
}
await subtractBlock.Completion;
}
catch(AggregateException e)
{
Console.WriteLine(e);
}
}
限制缓存为1,那么这时候我们就会相互切换。
下一章
整理:
1.数据流块的并行处理
2.创建自定义数据流块
参考
https://www.cnblogs.com/yswenli/p/8042594.html
并发系列64章(TPL 数据流)第七章的更多相关文章
- IDEA第七章----插件
idea的另一个可爱之处,就是它的强大的插件,下面我以CodeGlance插件为例,这个可以快速定位代码 第一节:安装插件 ● All plugins 显示所有插件. ● Enabled 显示当前所有 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (38) ------ 第七章 使用对象服务之动态创建连接字符串和从数据库读取模型
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第七章 使用对象服务 本章篇幅适中,对真实应用中的常见问题提供了切实可行的解决方案. ...
- 《Entity Framework 6 Recipes》中文翻译系列 (41) ------ 第七章 使用对象服务之标识关系中使用依赖实体与异步查询保存
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 7-7 标识关系中使用依赖实体 问题 你想在标识关系中插入,更新和删除一个依赖实体 ...
- [书籍翻译] 《JavaScript并发编程》第七章 抽取并发逻辑
本文是我翻译<JavaScript Concurrency>书籍的第七章 抽取并发逻辑,该书主要以Promises.Generator.Web workers等技术来讲解JavaScrip ...
- jQuery系列 第七章 jQuery框架DOM操作
第七章 jQuery框架的选择器 jQuery框架继承和优化了JavaScript访问DOM对象的特性,我们使用jQuery框架提供的api可以更加方便的操作DOM对象. 7.1 创建DOM节点 使用 ...
- 第七章 Rocketmq--消息驱动
今天咱们接着 上一篇第六章 Sleuth–链路追踪 继续写 SpringCloud Alibaba全家桶 , 第七章 Rocketmq--消息驱动,废话不多说,开始了 7.1 MQ简介 7.1.1 什 ...
- C primer plus 读书笔记第六章和第七章
这两章的标题是C控制语句:循环以及C控制语句:分支和跳转.之所以一起讲,是因为这两章内容都是讲控制语句. 第六章的第一段示例代码 /* summing.c --对用户输入的整数求和 */ #inclu ...
- 【原创】构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)—托管资源优化—监测CLR性能
原文:[原创]构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)-托管资源优化-监测CLR性能 构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)—托管资源优化—监测C ...
- 第七章——DMVs和DMFs(4)——用DMV和DMF监控磁盘IO
原文:第七章--DMVs和DMFs(4)--用DMV和DMF监控磁盘IO 前言: 本文为本系列最后一篇,作为DBA,你必须经常关注磁盘的I/O问题,一旦出现问题,要尽快分析出是什么问题.SQLServ ...
随机推荐
- Python文本文件读写操作时的字符编码问题
说明:文本文件的字符编码问题只存在t模式中,如:open('a.txt', mode='rt') 编码(encode): 我们输入的任何字符想要以文件(如.txt)的形式保存在计算机的硬盘上, 必须先 ...
- ArchLinux - 脚本安装使用指南
前面不想废话,讲什么脚本说明,功能什么的!只讲使用方法,其他的可以去Gitee看,去Github看. 脚本虽然支持Boot和UEFI,但是我打算一起讲,因为它们安装时的区别,只有3处不同. 第一步 先 ...
- 嵌入式LCD闪烁--emWin使用内存设备避免闪烁
0.引子 近日在论坛看到有人说屏幕闪烁,问道怎么解决.在嵌入式gui使用方面,屏幕闪烁一般多出现在多个窗口层叠.多图层层叠.更新图层时.受限于接口速度,即使屏幕有很高的刷新率,也做不到无闪烁,所以要从 ...
- C语言实现strcat / strlen / strcmp / strcpy
主要考虑两点: 返回值对使用的便利性. 边界,null的判断. strcat char *m_strcat(char *des, const char *src) { assert((des != N ...
- 利用Python获取文件类型
这里选择使用使用filetype获取文件的类型. 使用filetype之前,先用pip安装filetype. #!/usr/bin/python3 import filetype import arg ...
- OpenCV-Python 哈里斯角检测 | 三十七
目标 在本章中, 我们将了解"Harris Corner Detection"背后的概念. 我们将看到以下函数:cv.cornerHarris(),cv.cornerSubPix( ...
- 一文看懂NLP神经网络发展历史中最重要的8个里程碑!
导读:这篇文章中作者尝试将 15 年的自然语言处理技术发展史浓缩为 8 个高度相关的里程碑事件,不过它有些偏向于选择与当前比较流行的神经网络技术相关的方向.我们需要关注的是,本文中介绍的许多神经网络模 ...
- 一些数组笔记(C)
0.数组名是一个指针,存放数组首元素地址,所以使用scanf()接受字符串输入时只用写上数组名,不用加&.数组名是常量不允许修改其值.数组只能定义的时候初始化,后期初始化会被认为是修改数组名的 ...
- Nginx 实现API 网关
1,网关 网关(Gateway)就是一个网络连接到另一个网络的“关口”. 在Nginx 配置负载均衡之后,可以进入到网关,在网关决定进入到哪个真实的web 服务器. 2,将Ngnix 配置 API 网 ...
- Spring Framework之IoC容器
Spring IoC 概述 问题 1.什么是依赖倒置? 2.什么是控制反转? 3.什么是依赖注入? 4.它们之间的关系是怎样的? 5.优点有哪些? 依赖倒置原则 (Dependency Inversi ...