C#多线程开发之任务并行库

数据库2025-11-04 06:59:00951

本文转载自微信公众号「Andy阿辉」,线程行库作者阿辉 。线程行库转载本文请联系Andy阿辉公众号。线程行库

之前学习了线程池,线程行库知道了它有很多好处。线程行库

使用线程池可以使我们在减少并行度花销时节省操作系统资源。线程行库可认为线程池是线程行库一个抽象层,其向程序员隐藏了使用线程的线程行库细节,使我们可以专心处理程序逻辑,线程行库而不是线程行库各种线程问题。

但也不是线程行库说我们所有的项目中都上线程池,其实它也有很多弊端,线程行库比如我们需要自定义使用异步委托的线程行库方式才可以将线程中的消息或异常传递出来。这些如果在一个大的线程行库软件系统中,会导致软件结构过于混乱,线程行库各个线程之间消息传递来传递去的,如果发生没有处理掉的异常,很容易导致软件出现致命错误。

为了解决这个问题,在.Net Framework 4.0中引入了一个新的异步操作的API,它叫任务并行库(TPL)。

那么接下来,让我们一起来认识一下这个TPL,免费源码下载看看它到底有什么魔力可以把线程池中的棘手问题解决掉。

任务并行库

TPL又被认为是线程池的有一个抽象,其对程序员隐藏了线程池交互的底层代码,并只提供了更方便的细粒度的API。

TPL的核心是任务。一个任务代表一个异步操作,该操作可以通过多种方式运行,可以使用或不使用独立线程运行。

TPL有一个关键优势,就是一个任务可以通过多种方式和其它任务组合起来。

比如可以同时开启多个任务,等待所有任务完成,然后运行一个任务对之前所有任务的结果进行一些计算。

可以使用AggregateException来捕获底层任务内部所有异常,并允许单独处理这些异常。在C#5.0中已经内置了对TPL的支持,允许我们使用心得await和async关键字以平滑的、舒服的方式操作任务。

一、创建任务

可以通过下面三种方式来创建任务。亿华云计算

var a1 = new Task(()=>TastMethod("线程01"));       a1.Start();       Task.Run(()=>TastMethod("线程001"));    //已弃用       Task.Factory.StartNew(()=>TastMethod("线程02"));       Task.Factory.StartNew(() => TastMethod("线程03"),TaskCreationOptions.LongRunning);       Console.ReadKey(); 

在最新的.NET 5.0中已经将任务快速启动方式Run,丢弃掉了。只能使用其余的两种。实例化的Tast属性,必须进行启动,任务才可以执行。其余的.NET已经做了内置,只需要使用就默认自动开启。

在线程3开启过程中,增加了TaskCreationOptions.LongRuning参数,它表示标记该任务为长时间运行,结果该任务将不会使用线程池,而在单独的线程中运行。然而根据运行该任务的当前任务调度程序,运行方式可能不同。

二、使用任务执行基本操作

下面介绍下从任务中得到其计算法返回的结果。

static void Main(string[] args)        {               var a1 = new Task<int>(()=>TastMethod("线程01"));            a1.Start();            int result = a1.Result;                        Console.WriteLine("result:" + result);            Console.ReadKey();        }        static int TastMethod(string name)         {            Console.WriteLine("线程名字:"+name+"Id:"+Thread.CurrentThread.ManagedThreadId+"是否属于线程池:"+Thread.CurrentThread.IsThreadPoolThread);            return 40;        } 

输出结果

这里我们声明并运行了线程01并等待结果,该任务会被放置在线程池中,并且主线程会等待,直到任务返回前一直处于阻塞状态。

其实也可以调用方法RunSynchronously()方法,使其特定运行在主线程。这是一个非常好的免费信息发布网优化,可以避免使用线程池来执行非常短暂的操作。

三、处理任务中的异常

在异步任务中,对于异常的处理是非常重要的。

try {     var a1 = new Task<int>(() => TastMethod("线程01",2));     a1.Start();     int result = a1.Result;     Console.WriteLine("result:" + result); } catch (Exception ex) {     Console.WriteLine(ex.Message); }       

当程序启动时,创建了一个任务并尝试同步获取任务结果。Result属性的Get部分会使当前线程等待直到该任务结束,并将异常传播给当前线程。此时通过try/catch是很容易捕获到的(需要注意AggregateExceptiont,它被封装起来,)。

int result = a1.GetAwaiter().GetResult ; 

上面这种情况无需封装异常,可以使用GetAwaiter和GetResult方法来访问任务结果。

本文地址:http://www.bzuk.cn/news/191a32199487.html
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

全站热门

如何设置个性化开机密码提示界面(打造独一无二的电脑开机密码保护)

详解SQL语句的集合运算

深度解读 | 阿里云新一代关系型数据库 PolarDB

外媒速递:使用MongoDB时应当切实部署的五项数据库警报

电脑更新CF错误代码的解决方法(掌握解决CF错误代码的技巧,让游戏畅快进行)

通过 Inspector 收集 Node.js 的Trace Event 数据

降本增效!12 个必须尝试的Python工具包!

骞云科技:假如GitLab使用CMP管理PostgreSQL

友情链接

滇ICP备2023006006号-33