.NET并发编程-TPL Dataflow并行工作流
本系列学习在.NET中的并发并行编程模式,实战技巧
本小节了解TPL Dataflow并行工作流,在工作中如何利用现成的类库处理数据。旨在通过TDF实现数据流的并行处理。
TDF Block
数据流由一个一个的块组成,一个块处理完毕后链接到下一个块上。每一个块以消息的形式接收和缓存来自一个或多个源的数据,当接收到信息时,块通过将其行为应用于输入来作出反应,块的输出将传递到下一个块中。
TDF并不是作为.NET4.5框架的一部分分发,需要单独安装,用过nuget导入Microsoft.Tpl.Dataflow。4.5之上在System.Threading.Tasks.Dataflow类库中。TDF提供了一组丰富的组件(块),用于基于进程内消息传递语义来组合数据流和管道基础设施。
TDF最常用的块是标准的BufferBlock、ActionBlock和TransformBlock。它们每个都基于一个委托,该委托可以是匿名函数的形式,用于定义要计算的工作。
BufferBlock<TInput>
BufferBlock是一个很好的工具,用于启用和实现异步生产者/消费者模式,其中内部的消息队列可以由多个源写入或从多个目标读取。保证先进先出的顺序。
以下展示基于TDF BufferBlock的生产者消费者模式
BufferBlock<int> buffer = new BufferBlock<int>();
async Task Producer(IEnumerable<int> values)
{
foreach (var value in values)
await buffer.SendAsync(value);
buffer.Complete();
}
async Task Consumer(Action<int> process)
{
while (await buffer.OutputAvailableAsync())
process(await buffer.ReceiveAsync());
}
public async Task Run()
{
IEnumerable<int> range = Enumerable.Range(0, 100);
await Task.WhenAll(Producer(range), Consumer(n =>
Console.WriteLine($"value {n}")));
}
IEnumerable值的条目通过buffer.Post方法发送到BufferBlock缓冲区,并使用buffer.ReceiveAsync方法异步检索它们。OutputAvailableAsync方法用于当下一个条目准备好可被检索时发出通知。
TransformBlock<TInput,TOutput>
用于映射转换,该转换函数以委托Func<TInput,TOutput>的形式作为参数传递
给定一组地址下载图片为例
var fetchImageFlag = new TransformBlock<string, (string, byte[])>(
async urlImage =>
{
using (var webClient = new WebClient())
{
byte[] data = await webClient.DownloadDataTaskAsync(urlImage);
return (urlImage, data);
}
});
List<string> urlFlags = new List<string>{
"Italy#/media/File:Flag_of_Italy.svg",
"Spain#/media/File:Flag_of_Spain.svg",
"United_States#/media/File:Flag_of_the_United_States.svg"
};
foreach (var urlFlag in urlFlags)
fetchImageFlag.Post($"https://en.wikipedia.org/wiki/{urlFlag}");
TransformBlock<string, (string, byte[]) 块以元组字符串和字节数组格式来提取标记图像。转换得到字节数组对象后,此处还没有消费使用。下面通过另一个块组合将其保存到本地。
ActionBlock<TInput>
通过名称就可以看出,该块用于接收数据时调用一个委托去处理。因为它没有输出,所以通常用于工作流的结束节点上。
前面通过转换块将图片地址下载转换成了字节数组,下面通过ActionBlock将其持久化本地。
var saveData = new ActionBlock<(string, byte[])>(async data =>
{
(string urlImage, byte[] image) = data;
string filePath = urlImage.Substring(urlImage.IndexOf("File:") + 5);
await Agents.File.WriteAllBytesAsync(filePath, image);
});
fetchImageFlag.LinkTo(saveData);
ActionBlock块实例化传递给构造函数的参数可以是委托Action或Func<TInput,Task>。后者对每个消息输入异步执行内部操作。最后ActionBlock块saveData使用LinkTo扩展方法连接到前面的TransformBlock块上。通过这种方式,TransformBlock生成的输出会在可用时被立即推送到ActionBlock中。
最后粘贴一下File的扩展方法,用于异步读写文件。
public static class File
{
public static async Task<string[]> ReadAllLinesAsync(string path)
{
using (var sourceStream = new FileStream(path,
FileMode.Open, FileAccess.Read, FileShare.None,
bufferSize: 4096, useAsync: true))
using (var reader = new StreamReader(sourceStream))
{
var fileText = await reader.ReadToEndAsync();
return fileText.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
}
}
public static async Task WriteAllTextAsync(string path, string contents)
{
byte[] encodedText = Encoding.Unicode.GetBytes(contents);
await WriteAllBytesAsync(path, encodedText);
}
public static async Task WriteAllBytesAsync(string path, byte[] bytes)
{
using (var sourceStream = new FileStream(path,
FileMode.Append, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true))
{
await sourceStream.WriteAsync(bytes, 0, bytes.Length);
};
}
}
ending
第一次做人,何不痛痛快快,潇潇洒洒,讨好自己
工作认认真真的完成,生活充充实实的过着
.NET并发编程-TPL Dataflow并行工作流的更多相关文章
- 细说并发编程-TPL
本节导航 基本概念 并发编程 TPL 线程基础 windows为什么要支持线程 线程开销 CPU的发展 使用线程的理由 如何写一个简单Parallel.For循环 数据并行 Parallel.For剖 ...
- c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习
c#中@标志的作用 参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...
- 并发编程-TPL
并发编程-TPL 本节导航 基本概念 并发编程 TPL 线程基础 windows为什么要支持线程 线程开销 CPU的发展 使用线程的理由 如何写一个简单Parallel.For循环 数据并行 Para ...
- C#并发编程之初识并行编程
写在前面 之前微信公众号里有一位叫sara的朋友建议我写一下Parallel的相关内容,因为手中商城的重构工作量较大,一时之间无法抽出时间.近日,这套系统已有阶段性成果,所以准备写一下Parallel ...
- .NET并发编程-任务函数并行
本系列学习在.NET中的并发并行编程模式,实战技巧 请问普通: 被门夹过的核桃还能补脑吗 本小节开始学习基于任务的函数式并行.本系列保证最少代码呈现量,虽然talk is cheap, show me ...
- .NET的并发编程(TPL编程)是什么?
写在前面 优秀软件的一个关键特征就是具有并发性.过去的几十年,我们可以进行并发编程,但是难度很大.以前,并发性软件的编写.调试和维护都很难,这导致很多开发人员为图省事放弃了并发编程.新版 .NET 中 ...
- [翻译]在 .NET Core 中的并发编程
原文地址:http://www.dotnetcurry.com/dotnet/1360/concurrent-programming-dotnet-core 今天我们购买的每台电脑都有一个多核心的 C ...
- .NET Core 中的并发编程
今天我们购买的每台电脑都有一个多核心的 CPU,允许它并行执行多个指令.操作系统通过将进程调度到不同的内核来发挥这个结构的优点. 然而,还可以通过异步 I/O 操作和并行处理来帮助我们提高单个应用程序 ...
- c#并发编程经典实例文摘
第1章 并发编程概述 1.1 并发编程简介 并发: 多线程(包括并行处理) 异步编程(异步操作)程序启动一个操作,而该操作将会在一段时间后完成 响应时编程(异步事件)可以没有一个实际的开始,可以在任何 ...
随机推荐
- 敏捷史话(九):用做面包的方式做敏捷——Alistair Cockburn
在一次用例和敏捷技术交流大会上,Alistair给大家分享了自己比较崇尚的三个字: "守""破""离",他用做面包的例子,形象地将这三个字与 ...
- app渗透测试 服务端篇
基本知识 平时安装的应用位置,里面主要是odex可运行文件 /data/app 系统应用位置(需要root权限),里面主要是odex可运行文件 /system/app 应用的数据相关的位置,里面包含一 ...
- 使用Webpack构建多页面程序
使用webpack搭建单页面程序十分常见,但在实际开发中我们可能还会有开发多页面程序的需求,因此我研究了一下如何使用webpack搭建多页面程序. 原理 将每个页面所在的文件夹都看作是一个单独的单页面 ...
- Linux基础之Shell与变量
一.提出问题 在平时的工作中,我们经常会碰到设置环境的问题,例如将应用的执行路径添加到PATH中,方便程序的执行:在Linux中更多的时候是跟shell打交道,很多通过shell启动的应用或者服务都需 ...
- vue+django实现websocket连接
一.概述 在项目中,需要使用websocket,来展示一些实时信息. 这里使用django 3.1.5 二.django项目 安装模块 pip3 install django-cors-headers ...
- Java开发工程师面试-Web基础与数据处理
Servlet执行流程 客户端浏览器向Tomcat服务器发送Http请求 Tomcat解析web.xml文件,找到对应的url以及servlet-name,根据servlet-name找到对应的ser ...
- C# .NET Socket 简单实用框架,socket组件封装
参考资料 https://www.cnblogs.com/coldairarrow/p/7501645.html 根据.NET Socket 简单实用框架进行了改造,这个代码对socket通信封装还是 ...
- macbook/macOS下打开多个相同应用(应用多开)
1.部分应用可使用common+n快捷键.如qq:打开qq主界面后使用common+n即可新起一个qq程序. 2.在终端使用命令 open -n +程序路径.如启动多个qq : open -n /A ...
- Day1---Java 基本数据类型 - 四类八种 --九五小庞
一.Java四大数据类型分类 1.整型 byte .short .int .long 2.浮点型 float . double 3.字符型 char 4.布尔型 boolean 二.八种基本数据类型 ...
- SparkStreaming使用mapWithState时,设置timeout()无法生效问题解决方案
前言 当我在测试SparkStreaming的状态操作mapWithState算子时,当我们设置timeout(3s)的时候,3s过后数据还是不会过期,不对此key进行操作,等到30s左右才会清除过期 ...