3分钟总览微软TPL并行编程库
有小伙伴问我每天忽悠的TPL是什么?☹️ 这次站位高一点,严肃讲一讲。
引言
俗话说,不想开飞机的程序员不是一名好爸爸;作为微软技术栈的老鸟,一直将代码整洁之道奉为经典,
优秀的程序员将优雅、高性能的代码看成自己的脸面。
今天探讨下我对.NET并行编程库Task Parallel Library的理解,开足马力,准备压榨CPU了。
双核cpu的真相.gif
技术背景:
- 理解硬件线程和软件线程
多核处理器带有一个以上的物理内核: 物理内核是真正的独立处理单元,多个物理内核使得多条指令能够同时并行运行。
硬件线程也称为逻辑内核,一个物理内核可能使用超线程技术提供多个硬件线程,所以一个硬件线程并不代表一个物理内核。
我们通过程序中通过Environment.ProcessorCount
: 得到的就是逻辑内核(本人的机器是i5-5300U 虚拟4核),
Windows中每个运行的程序都是一个进程,每一个进程都会创建并运行一个或多个线程,这些线程称为软件线程,硬件线程就像是一条泳道,而软件线程就是在其中游泳的人。
并行场景
.NET引入的Task Parallel Library(任务并行库,TPL),动态地扩展并发度,以最有效的方式使用所有可用的处理器。
另外TPL支持分区工作、支持基于ThreadPool调度、支持取消异步操作、支持状态管理。
通过TPL专注与让程序完成你业务意义上的任务,同时最大限度的提高程序性能。
TPL同时支持数据并行、任务并行和流水线Dataflow
- 数据并行:有大量数据需要处理,并且必须对每一份数据执行同样的操作
- 任务并行:通过任务并发运行不同的操作。
- 流水线:这是任务并行和数据并行的结合体(需要引入System.Threading.Tasks.Dataflow组件库)
其中1.3 已经在上文演示。
数据并行
从100000个数中找到素数的个数
上文[共享内存并发模型],代码可做如下优化:
共享内存模型,只是有每个线程独立计算线程内迭代产生的素数和,最后再对几个和求和。
using System; using System.Threading.Tasks; using System.Collections; using System.Collections.Generic; using System.Threading; using System.Diagnostics; /// <summary> /// 利用并行编程库Parallel,计算100000内素数的个数 /// </summary> namespace Paralleler { class Program { static void Main(string[] args) { Stopwatch sw = new Stopwatch(); sw.Start(); ShareMemory(); sw.Stop(); Console.WriteLine($"优化后的共享内存并发模型耗时:{sw.Elapsed}"); } static void ShareMemory() { var sum = 0; Parallel.For(1, 100000 + 1, () => 0, (x, state, local) => { var f = true; if (x == 1) f = false; for (int i = 2; i <= x / 2; i++) { if (x % i == 0) // 被[2,x/2]任一数字整除,就不是质数 f = false; } if (f == true) local++; return local; }, local => { Interlocked.Add(ref sum, local); } ); Console.WriteLine($"1-100000内质数的个数是{sum}"); } } }
参数1,2 表示数据并行要操作的对象;
参数3localInit
表示某线程内迭代的初始值,将会作为参数4body
委托的第3个参数,只在线程第一次使用;
参数4body
表示每个迭代都需要经历的执行体, 这里以线程为单元处理迭代;
参数5localFinally
对每个线程的输出再做一次计算。入参是参数4的输出。
任务并行
让很多方法并行运行的最简单的方法就是使用Parallel类的Invoke方法,Invoke方法接受一个Action的参数组
。
System.Threading.Tasks.Parallel.Invoke(WatchMovie, HaveDinner, ReadBook, WriteBlog);
这段代码会创建指向每一个方法的委托。
没有特定的执行顺序
Parallel.Invoke方法只有在4个方法全部完成之后才会返回。它至少需要4个硬件线程才足以让这4个方法并发运行。但并不保证这4个方法能够同时启动运行,如果一个或者多个内核处于繁忙状态,那么底层的调度逻辑可能会延迟某些方法的初始化执行。
捕捉并行循环中发生的异常
当并行迭代中调用的委托抛出异常,这个异常没有在委托中被捕获到时,就会变成一组异常,新的System.AggregateException负责处理这一组异常。
本文为微软TPL入门级教程,学习一个专题,了解特性/能力最重要, 剩下的就是结合场景去应用。
本文来自博客园,作者:{有态度的马甲},转载请注明原文链接:https://www.cnblogs.com/JulianHuang/p/15036958.html
欢迎关注我的原创技术、职场公众号, 加好友谈天说地,一起进化
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?