.NET异步程序设计之任务并行库

目录

  • 1.简介
  • 2.Parallel类
    • 2.0 Parallel类简介
    • 2.1 Parallel.For()
    • 2.2 Parallel.ForEach()
    • 2.3 Parallel.Invoke()
    • 2.4 补充:线程安全集合
  • 3.Task类
    • 3.0 Task类简介
    • 3.1 创建无返回值的Task任务
    • 3.2 创建有返回值的Task任务
    • 3.3 为Task添加延续任务
    • 3.4 Task.Delay
    • 3.5 Task对象的其他一些静态方法
    • 3.6 取消异步操作
  • 4.并行Linq(PLinq)
    • 4.1 AsParallel()
    • 4.2 取消并行查询
  • 5.参考&源代码下载

shanzm-2020年2月16日 00:45:04


1.简介

System.Threading.Tasks中的类型被称为任务并行库(Task Parallel Library,TPL)。

System.Thread.Tasks 命名空间是.NET Framework4.0所提供,

“TPL使用CLR线程池(TPL是TreadPool的封装),自动将应用程序的工作,动态分配到可用的CPU中。TPL还处理工作分区、线程调度、状态管理和其他低级别的细节操作。最终结果是,你可以最大限度地提升.NET应用程序的性能,并且避免直接操作线程所带来的复杂性” --《精通C#》


 

2.Parallel类

 

2.0 Parallel类简介

System.Threading.Tasks命名空间下有一个静态类:Parallel类

Parallel可以实现对实现了IEnumerable接口的数据集合的每一个元素并行操作

有一点要说明的:并行操作会带来一定的成本,如果任务本身能很快完成,或是循环次数很少,那么并行处理的速度也许会比非并行处理还慢。

Parallel类就只有三个方法:Parallel.For()Parallel.ForEach()Parallel.Invoke()

但是呢,这每个方法都有大量的重载(F12-->自行查看Parallel定义)

 

2.1 Parallel.For()

使用Parallel.For()可以对数组中的每一个元素进行并行操作

正常的遍历数组是按照索引的顺序执行的;但是在并行操作下,对数组的每一个元素的操作不一定按照索引顺序操作

Parallel.For(),第一个参数是循环开始的索引(包含),第二个参数是循环结束的索引(不含)

Parallel.For()的第三个参数是一个有参数无返回值的委托,其参数是数组的索引

其实就相当于:for (int i = 0; i < length; i++)的异步版本,只是在这里是并行操作,所以并不按照数组中元素的顺序执行,具体的执行顺序是不可控的

示例

static void Main(string[] args)
{int[] intArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };Console.WriteLine("------------常规,对数组进行循环遍历------------");Array.ForEach(intArray, n => Console.WriteLine($"当前操作的数组元素是{n}"));//注意这里的参数n是元素而不是索引Console.WriteLine("------------并行操作 对数组进行循环遍历------------");Parallel.For(0, intArray.Length, (i) => Console.WriteLine($"当前循环次数{i},当前操作的数组元素是{intArray[i]}"));Console.ReadKey();
}

运行结果:可以看出,对数组的元素的操作顺序并不是按照索引的顺序,而是不确定的。

Parallel.For

 

2.2 Parallel.ForEach()

Parallel.ForEach()用于对泛型可枚举对象的元素进行并行操作

其实就相当于:foreach (var item in collection)的异步版本

Parallel.ForEach()有大量的重载,这里展示一个简单的操作

Parallel.ForEach()的第一个参数是待操作的可枚举对象,第二个参数是一个有参数无返回值的委托,该委托参数是集合的元素(而不是索引)

示例

List<int> intList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Parallel.ForEach(intList, n => Console.WriteLine(n+100));
Console.ReadKey();

 

2.3 Parallel.Invoke()

Parallel.Invoke()对指定一系列操作并行运算

参数是一个Action委托数组(注意只能是Action[],即只能是无返回值的委托数组)

Parallel.Invoke()最常见用于并发请求接口

示例:

static void Main(string[] args)
{Action action1=() =>{for (int i = 0; i < 5; i++){Console.WriteLine($"action-1-操作");}};Action action2 = () =>{for (int i = 0; i < 5; i++){Console.WriteLine($"action-2-操作");}};//Parallel.Invoke(action1, action2);Action[] actions = { action1, action2 };Parallel.Invoke(actions);Console.ReadKey();
}

运行结果:

Parallel.Invoke

 

2.4 补充:线程安全集合

详细可以参考微软的在线文档

多线程对同一个数据集合同时读写操作,可能会造成数据的混乱

.NET4 引入了System.Collections.Concurrent 命名空间,其中包含多个线程安全的数据集合类型。

现在的新项目中,只要是对数据集合进行多线程的增删操作,就应该使用并发集合类。

但是,如果仅从集合进行多线程的读取,则可使用一般的数据集合,即 System.Collections.Generic 命名空间中的类。

.net 中线程安全的数据集合有一下一些:

类型描述
BlockingCollection为实现 IProducerConsumerCollection 的所有类型提供限制和阻止功能。 有关详细信息,请参阅 BlockingCollection 概述。
ConcurrentDictionary键值对字典的线程安全实现。
ConcurrentQueueFIFO(先进先出)队列的线程安全实现。
ConcurrentStackLIFO(后进先出)堆栈的线程安全实现。
ConcurrentBag无序元素集合的线程安全实现。
IProducerConsumerCollection类型必须实现以在 BlockingCollection 中使用的接口。

一个简单的示例:给一个数据集合添加大批量的数据

List<int> list = new List<int>();
Parallel.For(0, 1000000, t => list.Add(t));

若是按照上面使用Parallel.For()的并行方式给List添加数据,

则会报错:“索引超出了数组界限。”或“ 源数组长度不足。请检查 srcIndex 和长度以及数组的下限。”

即使没有报错,list中的数据也是有问题的(比可能数量不足)

当然可以通过加锁的方式进行弥补:

List<int> list = new List<int>();
object locker = new object();
Parallel.For(0, 1000000, t => { lock(locker) { list.Add(t); } });

这样通过对操作的线程枷锁,完全是没有必要的,你可以使用线程安全的集合类型,比如在这里使用ConcurrentBag

ConcurrentBag<int> cBag = new ConcurrentBag<int>();
Parallel.For(0, 100000, t => cBag.Add(t));

当然因为是并行操作,所以插入集合中的数据并不是按照0-100000的顺序(仅仅是成段的有序)。


 


 

3.Task类

 

3.0 Task类简介

System.Threading.Tasks命名空间中Task类,表示异步操作。

Task类可以轻松地在次线程中调用方法,可以作为异步委托的简单替代品。

同时在该命名空间还有一个泛型Task<TResul>类,TResult 表示异步操作执行完成后返回值的类型。

创建一个Task操作,只需要使用静态函数Task.Run()即可,

Task.Run()是一个.net framework4.5及以上定义的一个默认异步操作,

Task.Run()参数是委托,即需要异步执行的方法,

注意作为Task.Run()的参数的委托都是无参委托

若Task.Run()参数是无返回值的委托Action,则Task.Run()返回值是Task类型

若Task.Run()参数是有返回值的委托Func<TResult>,则Task.Run()返回值是Task<TResult>泛型

注意:若是低于.net4.5,则可以使用Task.Factory.StartNew(),和Task.Run()静态方法作用一样

总而言之,言而总之,show you code ,一切皆明了!

 

3.1 创建无返回值的Task任务

示例:无返回值的Task

static void Main(string[] args)
{//1.使用Task构造函数创建,必须显式的使用.Start()才能开始执行//Task task = new Task(() => { Thread.Sleep(10); Console.WriteLine("我是Task ,我结束了"); });//task.Start();//2.使用TaskFactory.StartNew(工厂创建) 方法//Task task = Task.Factory.StartNew(() => { Thread.Sleep(10); Console.WriteLine("我是Task ,我结束了"); });//3.使用Task.Run()Task task = Task.Run(() => { Thread.Sleep(10); Console.WriteLine("我是Task.Run ,我结束了"); });if (!task.IsCompleted)//task.IsCompleted判断当前的任务是否已完成{Console.WriteLine("当前的Task.Run()尚未执行完,但是因为异步,返回到调用函数,所以可以先执行后续的代码");}Console.WriteLine("当前Task.Run还没有完成,我们是在他之后的代码但是先执行了");task.Wait();//强行锁定线程,等待task完成Console.WriteLine("终于Task.Run完成了工作");Console.ReadKey();
}

 

3.2 创建有返回值的Task任务

若是Task任务有返回值,返回值类型为Task<T>,使用返回值的Result属性查询具体值

调试时注意查看,运行到 Console.WriteLine(task.Result)的时候,其中Task任务还是在执行Thread.Sleep(1000)

还没有出结果,我们希望的异步执行也没有发生,而是程序是在一直在等待,这是为什么呢?

是因为一但执行了task.Result,即使task任务还没有完成,主线程则停下等待,直到等待task.Result出结果

这种情况和异步委托中调用EndInvoke()是一样的:一旦运行EndInvoke,若是引用方法还没有完成,主线程则停止,直到引用函数运行结束。

所以可以这样理解:task.Result可以看作是一个未来结果(一定有结果但还在运算中)

示例:有返回值的Task

static void Main(string[] args)
{Console.WriteLine("SomeDoBeforeTask");Func<int> Do = () => { Thread.Sleep(1000); Console.WriteLine("Task.Run结束"); return 2; };Task<int> task = Task.Run(Do);Console.WriteLine(task.Status);//使用task.Status查看当前的Task的状态:当前的状态:WaitingToRunConsole.WriteLine(task.Result);//使用task.result操作Task任务的返回值:返回值是:2Console.WriteLine(task.Status);//使用task.Status查看当前的Task的状态:当前的状态:RanToComplationConsole.WriteLine("SomeDoAfterTask");Console.ReadKey();
}

运行结果:

说明
其中我们使用task.Result查看当前的task的状态,其中Task的状态(即其生命周期)只有三种:

  • Created(创建Task):注意只有Task task=new Task(...),此时的Task状态为Created,其他方式创建的Task跳过了Created状态
  • WaitingToRun(等待执行Task)
  • RanToComplation(Task完成)

 

3.3 为Task添加延续任务

Task任务是在后台执行的同时,主线程的继续执行后续程序

所以有时候需要在Task结束后,继续执行某个特定的任务,即为Task添加延续任务(也称接续工作

举一个简单的例子,

求解1-5000能求被3整除的个数,这个过程需要许多时间,我把它定义为一个Task.Run()

我们需要在求出结果后打印出结果,这里怎么操作呢?

若是直接使用task.Result则会阻塞主线程,一直等待运算出结果,这显然不是我们想要的

若是使用while(!task.IsComplation){//后续操作},你无法判断Task何时结束,而且一旦Task结束则会中断后续操作

这里就是需要为Task加上接续工作

这里你可以明白,接续本质和异步委托中的回调模式是一样的,回调方法就是接续工作

 

3.3.1使用task.ContinueWith()

task1.ContinueWith(...task2..)表示当task1结束后接着运行task2任务

注意这里我们使用Lambda表达式编写接续工作,接续工作是有一个参数的,参数是Task类型,即上一个Task

即第一个Task完成后自动启动下一个Task,实现Task的延续

注意:ContinueWith()的返回值亦是Task类型对象,即新创建的任务

可以为接续工作task2继续添加接续工作task3

示例5 :

  static void Main(string[] args){Console.WriteLine("task执行前...");Task<int> task1 = Task.Run(() => Enumerable.Range(1, 5000).Count(n => (n % 3) == 0));Task task2 = task1.ContinueWith(t => Console.WriteLine($"当你看到这句话则task1结束了,1-5000中能被3整除的个数{t.Result}"));//这里的t就是task1Task task3 = task2.ContinueWith(t => Console.WriteLine($"当你看到这句话则task2也结束了"));Console.WriteLine($"task1及其接续工作正在执行中," + "\t\n" + "我们现在正在执行其他的后续代码");Console.ReadKey();}

运行结果:

 

3.3.2使用Awaiter

使用task.GetAwaiter()为相关的task创建一个等待者

示例:

    static void Main(string[] args){Console.WriteLine("task执行前...");Task<int> task1 = Task.Run(() => Enumerable.Range(1, 5000).Count(n => (n % 3) == 0));var awaiter = task1.GetAwaiter();//创建一个awaiter对象//awaiter.OnCompleted(() => Console.WriteLine($"当你看到这句话则task1结束了,1-5000中能被3整除的个{task1.Result}"));awaiter.OnCompleted(() => Console.WriteLine($"当你看到这句话则task1结束了,1-5000中能被3整除的个{awaiter.GetResult()}"));Console.WriteLine($"task1及其接续工作正在执行中," + "\t\n" + "我们现在正在执行其他的后续代码");Console.ReadKey();}

运行效果同上。

3.3.3使用ContinueWith和Awaiter的区别:

ContinueWith会返回Task对象,它非常适合用于增加更多的接续工作,不过,如果Task出错,必须直接处理AggregateException。

使用task.GetAwaiter创建awaiter对象,是在.net4.5之后,其中C#5.0的异步功能就是使用这种方式。

使用awaiter也是可以使用task.Result直接的查看任务的结果,但是使用awaiter.GetResult()可以在Task出现异常的时候直接抛出,不会封装在AggregateException中。

3.4 Task.Delay

延时执行Task

3.4.1 使用Task.Delay()和ContinueWith实现延迟工作

其实就相当于实现Thread.Sleep()的异步版本

若是你使用Thread.Sleep(),则会程序一直在等待(即阻塞线程),直到等待结束才会运行后续的代码

而这里就相当于给给Thread.Sleep()一个加了接续工作,且这个接续工作是异步的。

即使用Task.Delay()不会阻塞主线程,主线程可以继续执行后续代码

示例:

    //新建异步任务,30毫秒秒后执行Task.Delay(30).ContinueWith(c =>{for (int i = 0; i < 50; i++){Console.WriteLine(i + "这是Task在运行");}});for (int i = 0; i < 100; i++){Console.WriteLine(i + "这是Task之后的程序在运行");}

调试的时候你会发现,刚开始的时候的时候是先显示的"i这是Task之后的程序在运行"

之后在等带了30毫秒,后就会开始显示"i这是Task在运行"和"i这是Task之后的程序在运行"交叉显示

运行结果如下:

 

3.4.2 使用Task.Delay()和Awaiter实现延迟工作

示例:运行效果同上

    Task.Delay(30).GetAwaiter().OnCompleted(() =>{for (int i = 0; i < 50; i++){Console.WriteLine(i + "这是Awaiter在运行行");}});for (int i = 0; i < 100; i++){Console.WriteLine(i + "这是Awaiter之后的程序在运行行");}Console.ReadKey();    

 

3.5 Task对象的其他一些静态方法

方法名说明
Task.Waittask1.Wait();就是等待任务执行(task1)完成,task1的状态变为Completed
Task.WaitAll待所有的任务都执行完成
Task.WaitAny发同Task.WaitAll,就是等待任何一个任务完成就继续向下执行
CancellationTokenSource通过cancellation的tokens来取消一个Task

 

3.6 取消异步操作

异步方法是可以请求终止运行的,

System.Threading.Tasks命名空间中有两个类是为此目的而设计的:Cance1lationToken和CancellationTokenSource。

下面看使用CancellationTokenSource和CancellationToken来实现取消某个异步操作。

这里使用Task.Run()为例,其第一个参数是一个Action委托,第二个参数就是CancellationToken对象

static void Main(string[] args)
{CancellationTokenSource cts = new CancellationTokenSource();//生成一个CancellationTokenSource对象,该对象可以创建CancellationToken                                                 CancellationToken ct = cts.Token;//获取一个令牌(token)Task.Run(() =>{for (int i = 0; i < 20; i++){if (ct.IsCancellationRequested){return;}Thread.Sleep(1000);Console.WriteLine($"异步程序的的循环:{i}");}}, ct);//注意Run()的第二个参数就是终止令牌tokenfor (int i = 0; i < 4; i++){Thread.Sleep(1000);Console.WriteLine($"主线程中循环:{i}");}Console.WriteLine("马上sts.Cancel(),即将要终止异步程序");cts.Cancel();//含有该CancellationTokenSource的token的异步程序,终止!Console.ReadKey();
}

运行结果:可以发现异步任务Task.Run()还没有完成,但是因为cst.Cancel()运行,token的属性IsCancellationRequested变为true,异步循环结束。

说明:取消一个异步操作的过程,注意,该过程是协同的。

即:调用CancellationTokenSource的Cancel时,它本身并不会执行取消操作。
而是会将CancellationToken的IsCancellationRequested属性设置为true。
包含CancellationToken的代码负责检查该属性,并判断是否需要停止执行并返回。


 


 

4.并行Linq(PLinq)

 

4.1 AsParallel()

System.Linq名称空间中有一个ParallelEnumerable类,该类中的方法可以分解Linq查询的工作,使其分布在多个线程上,即实现并行查询。

为并行运行而设计的LINQ查询称为PLINQ查询

下面让我们先简单的理一理:

首先我们都知道Enumerable类为IEnumberable<T>接口扩展了一系列的静态方法。(就是我们使用Linq方法语法的中用的哪些常用的静态方法,自行F12)

正如MSDN中所说:“ParallelEnumberable是Enumberable的并行等效项”,ParallelEnumberable类则是Enumerable类的并行版本,

F12查看定义可以看到ParallelEnumerable类中几乎所有的方法都是对ParallelQuery<TSource>接口的扩展,

但是,在ParallelEnumberable类有一个重要的例外,AsParallel() 方法还对IEnumerable<T>接口的扩展,并且返回的是一个ParallelQuery<TSource>类型的对象,

所以呢?凡是实现类IEnumberable<T>集合可以通过调用静态方法AsParallel(),返回一个ParallelQuery类型的对象,之后就可以使用ParallelEnumerable类中的异步版本的静态查询方法了!

注意在运行PLinq的时候,PLinq会自动的判断如果查询能从并行化中受益,则将同时运行。而如果并行执行查询会损害性能,PLINQ将按顺序运行查询。

示例:求1到50000000中可以整除3的数,将所求的结果倒序存放在modThreeIsZero[]中

这是需要非常多的重复运算,所以我们可以对比按照一般Linq查询下方式和PLinq查询,对比一些需要的时间。

static void Main(string[] args)
{int[] intArray = Enumerable.Range(1, 50000000).ToArray();Stopwatch sw = new Stopwatch();//顺序查询sw.Start();int[] modThreeIsZero1 = intArray.Select(n => n).Where(n => n % 3 == 0).OrderByDescending(n => n).ToArray();sw.Stop();Console.WriteLine($"顺序查询,运行时间:{sw.ElapsedMilliseconds}毫秒,可以整除3的个数:{modThreeIsZero1.Count()}");//使用AsParallel()实现并行查询//AsParallel()方法返回ParallelQuery&lt;TSourc>类型对象。因为返回的类型,所以编译器选择的Select()、Where()等方法是ParallelEnumerable.Where(),而不是Enumerable.Where()。sw.Restart();int[] modThreeIsZero2 = intArray.AsParallel().Select(n => n).Where(n => n % 3 == 0).OrderByDescending(n => n).ToArray();sw.Stop();Console.WriteLine($"并行查询,运行时间:{sw.ElapsedMilliseconds}毫秒,可以整除3的个数:{modThreeIsZero2.Count()}");Console.ReadKey();
}

说明:AsParallel()方法返回ParallelQuery<TSourc>类型对象。因为返回的类型,所以编译器选择的Select()、Where()等方法是ParallelEnumerable.Where(),而不是Enumerable.Where()。

运行结果:

可以对比结果,在大规模的Linq查询中,同步查询和并行查询两者的运行时间的差距还是很大的!

但是小规模的Linq查询二者的效果其实并没有很明显。

4.2 取消并行查询

在3.6取消异步操作中解释了如何取消一个长时间的任务,

那么对于长时间运行的PLinq也是可以取消的

同样是使用CancellationTokenSource生成一个CancellationToken对象作为token

怎么把token给PLinq呢?使用ParallelQuery<TSource>中静态方法WithCancellation(token)

在PLinq中,若是取消了并行操作,则会抛出OperationCanceledException

示例:

static void Main(string[] args)
{//具体的作用和含义可以看0030取消一个异步操作CancellationTokenSource cts = new CancellationTokenSource();CancellationToken ct = cts.Token;int[] intArray = Enumerable.Range(1, 50000000).ToArray();Task<int[]> task = Task.Run(() =>{try{int[] modThreeIsZero = intArray.AsParallel().WithCancellation(ct).Select(n => n).Where(n=> n% 3 == 0).OrderByDescending(n => n).ToArray();return modThreeIsZero;}catch (OperationCanceledException ex)//一旦PLinq中取消查询就会触发OperationCanceledException异常{Console.WriteLine(ex.Message);//注意:Message的内容就是:已取消该操作return null;}});Console.WriteLine("取消PLinq?Y/N");string input = Console.ReadLine();if (input.ToLower().Equals("y")){cts.Cancel();//取消并行查询Console.WriteLine("取消了PLinq!");//undone:怎么验证已经真的取消了}else{Console.WriteLine("Loading……");Console.WriteLine(task.Result.Count());}Console.ReadKey();
}


 


 

5.参考&源代码下载

书籍:精通C#

书籍:C#高级编程

书籍:ASP.NET MVC5网站开发之美

文档:.NET API 浏览器

点击:源代码下载

唉,书真是越看越厚,皆是浅尝辄止,先到这里吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438235.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mysql主从延时解决办法

1.忍受大法 第一种解决办法&#xff0c;很简单&#xff0c;无他&#xff0c;不管他&#xff0c;没有读到也没事。这时业务不需要任何改造&#xff0c;你好&#xff0c;我好&#xff0c;她也好~ 如果业务对于数据一致性要求不高&#xff0c;我们就可以采用这种方案。 2.数据同…

关于C#程序的单元测试

目录 1.单元测试概念2.单元测试的原则3.单元测试简单示例4.单元测试框架特性标签5.单元测试中的断言Assert6.单元测试中验证预期的异常7.单元测试中针对状态的间接测试8.单元测试在MVC模式中的实现8.单元测试相关参考9.示例源代码下载 志铭-2020年1月23日 11:49:41 1.单元测试…

NuGet是什么?理解与使用(上)

如果你了解python&#xff0c;那么它类似pip。 如果你了解nodejs&#xff0c;那么它类似npm。 如果你了解ruby&#xff0c;那么它类似gem。 对&#xff0c;它就是一个包&#xff08;package&#xff09;管理平台&#xff0c;确切的说是 .net平台的包管理工具&#xff0c;它提…

NuGet是什么?理解与使用(下)

本篇将回答下面几个问题&#xff1a; 如何解读NuGet Gallery上的包信息&#xff1f;如何上传NuGet包到NuGet Gallery&#xff1f;如何安装本地NuGet包&#xff1f;NuGet包的内容文件与目录结构&#xff1f; 如果你没看过上篇那么它在这里&#xff1a; 6号咸鱼&#xff1a;NuG…

C#多线程之旅(1)——介绍和基本概念

阅读目录 一、多线程介绍二、Join 和Sleep三、线程怎样工作四、线程和进程五、线程的使用和误用一、多线程介绍 C#通过多线程支持并行执行的代码。一个线程是一个独立执行的路径&#xff0c;可以同时与其他线程一起运行。一个C#客户端程序(Console,WPF,Winows Forms)开始于一个…

C#多线程之旅(2)——详解线程的开始和创建

阅读目录 代码下载一、线程的创建和开始二、传递数据给一个线程三、命名线程四、前台线程和后台线程五、线程优先级六、异常处理代码下载 Thread_博客园_cnblogs_jackson0714.zip 第一篇~第三篇的代码示例&#xff1a; 源码地址&#xff1a;https://github.com/Jackson0714/T…

C#多线程之旅(3)——线程池

阅读目录 代码下载一、介绍二、通过TPL进入线程池三、不用TPL进入到线程池v博客前言 先交代下背景&#xff0c;写《C#多线程之旅》这个系列文章主要是因为以下几个原因&#xff1a;1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的&#xff0c;如果没有…

C#多线程之旅(4)——APM初探

阅读目录 一、简单的串行执行程序 二、使用委托来实现APM源码地址&#xff1a;https://github.com/Jackson0714/Threads C#多线程之旅(4)——APM初探 v博客前言 先交代下背景&#xff0c;前面几张内容主要是介绍多线程的基本知识&#xff0c;这一章是因为正好接触到了APM&…

C#多线程编程系列(五)- C# ConcurrentBag的实现原理

目录 一、前言二、ConcurrentBag类三、 ConcurrentBag线程安全实现原理 1. ConcurrentBag的私有字段2. 用于数据存储的ThreadLocalList类3. ConcurrentBag实现新增元素4. ConcurrentBag 如何实现迭代器模式四、总结笔者水平有限&#xff0c;如果错误欢迎各位批评指正&#xff…

C#多线程编程系列(五)- 浅析C# Dictionary实现原理

目录 一、前言二、理论知识 1、Hash算法2、Hash桶算法3、解决冲突算法三、Dictionary实现 1. Entry结构体2. 其它关键私有变量3. Dictionary - Add操作4. Dictionary - Find操作5. Dictionary - Remove操作6. Dictionary - Resize操作(扩容)7. Dictionary - 再谈Add操作8. Col…

ASP.NET MVC 入门5、View与ViewData

本系列文章基于ASP.NET MVC Preview5. view在MVC模式中与用户进行最直接的接触&#xff0c;它负责数据的呈现。这里要注意一点就是&#xff0c;view只是负责数据的呈现&#xff0c;所以我们应该要尽量让view中不涉及业务逻辑的处理。 我们来添加一个Blog首页的view。在安装了…

ASP.NET MVC 入门6、TempData

本系列文章基于ASP.NET MVC Preview5. ASP.NET MVC的TempData用于传输一些临时的数据&#xff0c;例如在各个控制器Action间传递临时的数据或者给View传递一些临时的数据&#xff0c;相信大家都看过“在ASP.NET页面间传值的方法有哪几种”这个面试题&#xff0c;在ASP.NET MVC…

ASP.NET MVC 入门11、使用AJAX

本系列文章基于ASP.NET MVC beta.本示例Blog系统同步更新的演示站点&#xff1a;http://4mvcblog.qsh.in/ 在ASP.NET MVC beta发布之前&#xff0c;M$就宣布支持开源的JS框架jQuery&#xff0c;然后ASP.NET MVC beta发布后&#xff0c;你建立一个ASP.NET MVC beta的项目后&…

Nacos 使用

环境准备 64 bit OS&#xff0c;支持 Linux/Unix/Mac/Windows&#xff0c;推荐选用 Linux/Unix/Mac。64 bit JDK 1.8&#xff1b;下载 & 配置。Maven 3.2.x&#xff1b;下载 & 配置。 下载 Nacos 并启动 Nacos server。 启动配置管理 启动了 Nacos server 后&#x…

四种并发编程模型简介

概述 并发往往和并行一起被提及&#xff0c;但是我们应该明确的是“并发”不等同于“并行” • 并发 &#xff1a;同一时间 对待 多件事情 &#xff08;逻辑层面&#xff09; • 并行 &#xff1a;同一时间 做(执行) 多件事情 (物理层面) 并发可以构造出一种问题解…

从编译到执行,C++如何开发SIMD友好的代码?

一&#xff1a;名词解释 Flynn分类法 Flynn于1972年提出了计算平台的Flynn分类法,主要根据指令流和数据流来分类。按照Flynn分类法&#xff0c;计算平台共分为四种类型。 1.单指令流单数据流机器(SISD) 2.单指令流多数据流机器(SIMD) 3.多指令流单数据流机器(MISD) 4.多指令流…

Nacos介绍

Nacos 英文全称为 Dynamic Naming and Configuration Service&#xff0c;是一个由阿里巴巴团队使用 Java 语言开发的开源项目。 参考:home (nacos.io) Nacos 是一个更易于帮助构建云原生应用的动态服务发现、配置和服务管理平台&#xff0c;可以将 Nacos 理解成服务注册中心…

在部署 C#项目时转换 App.config 配置文件

问题 部署项目时&#xff0c;常常需要根据不同的环境使用不同的配置文件。例如&#xff0c;在部署网站时可能希望禁用调试选项&#xff0c;并更改连接字符串以使其指向不同的数据库。在创建 Web 项目时&#xff0c;Visual Studio 自动生成了 Web.config、Web.Debug.config、We…

设计模式之Factory

设计模式之Factory 2016-08-04 11:57 设计模式总共有23种模式这种都仅仅是为了一个目的&#xff1a;解耦解耦解耦...&#xff08;高内聚低耦合满足开闭原则&#xff09; 介绍: Factory Pattern有3种当然是全部是creational pattern。 1.Simple Factory Pattern 2.Factory…

C#多线程之旅(七)——终止线程

阅读目录 一、什么时候用Thread.Abort();二、Thread.Abort的用法三、无法终止线程的情形四、Catch块中抛出异常五、Finally块中抛出异常六、Abort调用的时间先交代下背景&#xff0c;写《C#多线程之旅》这个系列文章主要是因为以下几个原因&#xff1a;1.多线程在C/S和B/S架构中…