C#多线程开发之任务并行库
时间:2025-11-05 15:16:35 出处:综合阅读(143)

本文转载自微信公众号「Andy阿辉」,线程行库作者阿辉 。线程行库转载本文请联系Andy阿辉公众号。线程行库
之前学习了线程池,线程行库知道了它有很多好处。线程行库
使用线程池可以使我们在减少并行度花销时节省操作系统资源。线程行库可认为线程池是线程行库一个抽象层,其向程序员隐藏了使用线程的线程行库细节,使我们可以专心处理程序逻辑,线程行库而不是线程行库各种线程问题。
但也不是线程行库说我们所有的项目中都上线程池,其实它也有很多弊端,线程行库比如我们需要自定义使用异步委托的线程行库方式才可以将线程中的消息或异常传递出来。这些如果在一个大的线程行库软件系统中,会导致软件结构过于混乱,线程行库各个线程之间消息传递来传递去的,如果发生没有处理掉的异常,很容易导致软件出现致命错误。
为了解决这个问题,在.Net Framework 4.0中引入了一个新的异步操作的API,它叫任务并行库(TPL)。
那么接下来,让我们一起来认识一下这个TPL,站群服务器看看它到底有什么魔力可以把线程池中的棘手问题解决掉。
任务并行库
TPL又被认为是线程池的有一个抽象,其对程序员隐藏了线程池交互的底层代码,并只提供了更方便的细粒度的API。
TPL的核心是任务。一个任务代表一个异步操作,该操作可以通过多种方式运行,可以使用或不使用独立线程运行。
TPL有一个关键优势,就是一个任务可以通过多种方式和其它任务组合起来。
比如可以同时开启多个任务,等待所有任务完成,然后运行一个任务对之前所有任务的结果进行一些计算。
可以使用AggregateException来捕获底层任务内部所有异常,并允许单独处理这些异常。在C#5.0中已经内置了对TPL的支持,允许我们使用心得await和async关键字以平滑的、舒服的方式操作任务。
一、创建任务
可以通过下面三种方式来创建任务。b2b信息网
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方法来访问任务结果。
猜你喜欢
- 你可能已经知道如何将你的 Ubuntu 桌面升级到最新版本了,不过假如你用的 Ubuntu Server,而且也正好又希望升级一下的话(前提是,不会影响你的应用。一般来说,对于服务器操作系统,应该采用保守态度。假如不是必须升级才能解决的安全问题,最好不要升级,而是采用各种外部手段来解决。)假如想从Ubuntu14.04/13.10/13.04/12.10/12.04或者更老的版本升级到14.10,只要遵循下面给出的步骤。注意,你不能直接从13.10升级到14.10。你应该先将13.10升级到14.04在从14.04升级到14.10。下面是详细步骤。下面的步骤不仅能用于14.10,也兼容于一些像Lubuntu14.10,Kubuntu14.10和Xubuntu14.10等的Ubuntu衍生版本重要:在升级之前,保险起见,不要忘了将你的数据在U盘或外部硬盘上保存一下。服务器升级从ubuntu14.04的服务器升级到14.10的服务器,采用下面的步骤。安装update-manager-core 这个包假如之前没唷安装的话:复制代码代码如下:sudo apt-get install update-manager-core编辑 /etc/update-manager/release-upgrades这个文件。复制代码代码如下:sudo nano /etc/update-manager/release-upgrades像下面那样设置Prompt=normal或者Prompt=lts复制代码代码如下:# Default behavior for the release upgrader. [DEFAULT] # Default prompting behavior, valid options: # # never - Never check for a new release. # normal - Check to see if a new release is available. If more than one new # release is found, the release upgrader will attempt to upgrade to # the release that immediately succeeds the currently-running # release. # lts - Check to see if a new LTS release is available. The upgrader # will attempt to upgrade to the first LTS release available after # the currently-running one. Note that this option should not be # used if the currently-running release is not itself an LTS # release, since in that case the upgrader wont be able to # determine if a newer release is available. Prompt=normal现在可以通过下面的命令来更新你的服务系统了。复制代码代码如下:sudo do-release-upgrade -d直到屏幕提示你已完成。
- MySQL Server has gone away报错原因汇总版
- 聊聊 Sentry Relay 二次开发调试
- 为何过了PMP项目经理认证,还是无法做好IT项目管理?
- 学习PS的基础知识及技巧(掌握PS软件操作,提升设计能力)
- 小心!Objects.equals有坑
- Dataset基于SQLAlchemy的便利工具
- interface和type有什么区别吗?你知道吗?
- 小新iPad电脑模式教程(快速掌握小新iPad电脑模式的使用技巧)