有小伙伴问我每天忽悠的TPL是什么?☹️ 这次站位高一点,严肃讲一讲。

引言

俗话说,不想开飞机的程序员不是一名好爸爸;作为微软技术栈的老鸟,一直将代码整洁之道奉为经典,

优秀的程序员将优雅、高性能的代码看成自己的脸面。

今天探讨下我对.NET并行编程库Task Parallel Library的理解,开足马力,准备压榨CPU了。



双核cpu的真相.gif

技术背景:

  1. 理解硬件线程和软件线程

多核处理器带有一个以上的物理内核: 物理内核是真正的独立处理单元,多个物理内核使得多条指令能够同时并行运行。

硬件线程也称为逻辑内核,一个物理内核可能使用超线程技术提供多个硬件线程,所以一个硬件线程并不代表一个物理内核。

我们通过程序中通过Environment.ProcessorCount: 得到的就是逻辑内核(本人的机器是i5-5300U 虚拟4核),

Windows中每个运行的程序都是一个进程,每一个进程都会创建并运行一个或多个线程,这些线程称为软件线程,硬件线程就像是一条泳道,而软件线程就是在其中游泳的人。

并行场景

.NET引入的Task Parallel Library(任务并行库,TPL),动态地扩展并发度,以最有效的方式使用所有可用的处理器。

另外TPL支持分区工作、支持基于ThreadPool调度、支持取消异步操作、支持状态管理。

通过TPL专注与让程序完成你业务意义上的任务,同时最大限度的提高程序性能。

TPL同时支持数据并行、任务并行和流水线Dataflow

  1. 数据并行:有大量数据需要处理,并且必须对每一份数据执行同样的操作
  2. 任务并行:通过任务并发运行不同的操作。
  3. 流水线:这是任务并行和数据并行的结合体(需要引入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入门级教程,学习一个专题,了解特性/能力最重要, 剩下的就是结合场景去应用。

3分钟总览微软TPL并行编程库的更多相关文章

  1. Task C# 多线程和异步模型 TPL模型 【C#】43. TPL基础——Task初步 22 C# 第十八章 TPL 并行编程 TPL 和传统 .NET 异步编程一 Task.Delay() 和 Thread.Sleep() 区别

    Task C# 多线程和异步模型 TPL模型   Task,异步,多线程简单总结 1,如何把一个异步封装为Task异步 Task.Factory.FromAsync 对老的一些异步模型封装为Task ...

  2. [转载]:Delphi xe7并行编程快速入门

    现在多数设备.计算机都有多个CPU单元,即使是手机也是多核的.但要在开发中使用多核的优势,却需要一些技巧,花费时间编写额外的代码.好了,现在可以使用Delphi做并行编程了. 在Delphi.C++ ...

  3. 关于delphi XE7中的动态数组和并行编程(第一部分)

    本文引自:http://www.danieleteti.it/category/embarcadero/delphi-xe7-embarcadero/ 并行编程库是delphi XE7中引进的最受期待 ...

  4. Delphi xe7并行编程快速入门(三篇)

    现在多数设备.计算机都有多个CPU单元,即使是手机也是多核的.但要在开发中使用多核的优势,却需要一些技巧,花费时间编写额外的代码.好了,现在可以使用Delphi做并行编程了. 在Delphi.C++ ...

  5. Delphi xe7并行编程快速入门(转)

    源:http://blog.csdn.net/henreash/article/details/41315183 现在多数设备.计算机都有多个CPU单元,即使是手机也是多核的.但要在开发中使用多核的优 ...

  6. Delphi XE7并行编程: 并行For循环

    从Delphi XE7开始,引入了全新的并行编程库用于简化并行编程,它位于System.Threading单元中. 下面是一个判断素数的简单例子:function IsPrime (N: Intege ...

  7. TPL异步并行编程之简单使用

    并行编程一直是一个老生常谈的话题 在这里记录一下TPL编程,这在net4.0 微软就已经提供了多核时代下的并行库,其中最核心的最常用的也就是Task 一 Task是什么 Task可以简单的理解为一个线 ...

  8. C#中的多线程 - 并行编程 z

    原文:http://www.albahari.com/threading/part5.aspx 专题:C#中的多线程 1并行编程Permalink 在这一部分,我们讨论 Framework 4.0 加 ...

  9. .NET并行编程1 - 并行模式

    设计模式——.net并行编程,清华大学出版的中译本. 相关资源地址主页面: http://parallelpatterns.codeplex.com/ 代码下载: http://parallelpat ...

  10. 【读书笔记】.Net并行编程高级教程--Parallel

    一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控>这本书中也多次提到并发,不管是计算机 ...

随机推荐

  1. [转帖]TIDB - 使用BR工具进行数据热备份与恢复

    一.BR工具 BR 全称为 Backup & Restore,是 TiDB 分布式备份恢复的命令行工具,用于对 TiDB 集群进行数据备份和恢复.BR 只支持在 TiDB v3.1 及以上版本 ...

  2. Python学习之十_paramiko的简单学习

    Python学习之十_paramiko的简单学习 简介 pywinrm 是python用于连接访问windows的工具 paramiko 是python用于连接访问linux的工具 ansible等工 ...

  3. top的简单学习

    获取当前进程的全部线程 jps 获取jvm的进程信息. top -Hp $pid -bn 1 > 1.txt 可以获取当前特定进程的所有子进程. 注意linux与Windows的不太一样. li ...

  4. 各开发语言DNS缓存配置建议

    作者:翟贺龙 一.背景 在计算机领域,涉及性能优化动作时首先应被考虑的原则之一便是使用缓存,合理的数据缓存机制能够带来以下收益: 1.缩短数据获取路径,热点数据就近缓存以便后续快速读取,从而明显提升处 ...

  5. 【杂题,树】【Uoj】Uoj618 【JOISC2021】聚会 2

    2023.7.3 Problem Link 给定一棵 \(n\) 个点的树,对于一个点集 \(S\),定义 \(f(u,S)\) 为 \(\min_u \sum_{v\in S} \mathrm{di ...

  6. ABP-VNext 用户权限管理系统实战02---用户权限表的创建与迁移

    一.表实体建立 1.菜单表 [Comment("菜单表")] [Table("t_identity_menu")] public class Menu : Au ...

  7. 根据TxID获取上链数据

    根据TxID获取上链信息 前段时间应甲方爸爸的要求,需要在现有的业务系统中新增一个根据TxID来查询上链信息的接口.搜了一圈发现相关的信息很少,最后只能祭出终极大招:Read Source Code. ...

  8. P7036 [NWRRC2016] Folding

    题目简述 有两个矩形,大小分别是 \(W \times Y\) 和 $ w \times y$.现在我们要通过折叠将两个矩阵变成一样. 思路 part1 已知一条边折叠一次会变成 \(\frac{x} ...

  9. C# 求两个时间的差值

    商品保质期 //dateStart:系统时间: dateEnd :物品到期日期 DateTime dateStart = DateTime.Now.Date;//2021/7/8 DateTime d ...

  10. 常见的for循环优化方式

    ?> 前言 经常使用一些循环,进行耗时计算的操作,特别是 for 循环,它是一种重复计算的操作,如果处理不好,耗时就比较大,如果处理书写得当,将大大提高效率,下面总结几条 for 循环的常见优化 ...