一起谈.NET技术,4.0中的并行计算和多线程详解(二)

简介:   相关文章:4.0中的并行计算和多线程详解(一)  多线程部分  多线程在4.0中被简化了很多,仅仅只需要用到System.Threading.Tasks.::.Task类,下面就来详细介绍下Task类的使用。

  相关文章:4.0中的并行计算和多线程详解(一)

  多线程部分

  多线程在4.0中被简化了很多,仅仅只需要用到System.Threading.Tasks.::.Task类,下面就来详细介绍下Task类的使用。

  一、简单使用

  开启一个线程,执行循环方法,返回结果。开始线程为Start(),等待线程结束为Wait()。

Code
  1.         /// <summary>
  2.         /// Task简单使用
  3.         /// </summary>
  4.         private void Demo1()
  5.         {
  6.             int i = 0;
  7.             Random r = new Random(DateTime.Now.Second);
  8.             Task t = new Task(() =>
  9.             {
  10.                 for (int v = 0; v < 100; v++)
  11.                     i += r.Next(100);
  12.             });
  13.             t.Start();
  14.             t.Wait();
  15.             Console.WriteLine("这是执行Task1后等待完成:" + i.ToString());
  16.             Console.ReadLine();
  17.         }

  比以前使用Thread方便多了吧。上面的例子是使用外部的变量获得结果,下面的例子是用Task<T>直接返回结果,当调用Result属性时,会自动等待线程结束,等同调用了Wait()。代码如下:

Code
  1.         /// <summary>
  2.         /// Task带返回值
  3.         /// </summary>
  4.         private void Demo2()
  5.         {
  6.             Random r = new Random(DateTime.Now.Second);
  7.             Task<int> t = new Task<int>(() =>
  8.             {
  9.                 int i = 0;
  10.                 for (int v = 0; v < 100; v++)
  11.                     i += r.Next(100);
  12.                 return i;
  13.             });
  14.             t.Start();
  15.             Console.WriteLine("这是执行Task1获取返回值:" + t.Result.ToString());
  16.             Console.ReadLine();
  17.         }

  总结1:Task的使用比Thread简单很多,减少了同步,等待等等问题,唯一的遗憾是不支持Thread的IsBackground。

  结论1:如果不需要使用IsBackground,那么尽情的使用Task吧。

  二、线程执行完毕后调用另一个线程

  也就是两个线程,有序的执行,这里使用ContinueWith(),t执行完毕后再执行一个task方法,不多说了代码如下:

Code
  1.         /// <summary>
  2.         /// Task 执行完毕后调用另一个Task
  3.         /// </summary>
  4.         private void Demo3()
  5.         {
  6.             Random r = new Random(DateTime.Now.Second);
  7.             Task<int> t = new Task<int>(() =>
  8.             {
  9.                 int i = 0;
  10.                 for (int v = 0; v < 100; v++)
  11.                     i += r.Next(100);
  12.                 return i;
  13.             });
  14.             t.ContinueWith((Task<int> task) =>
  15.             {
  16.                 Console.WriteLine("这是执行完毕Task1后继续调用Task2:" + task.Result.ToString());
  17.             });
  18.             t.Start();
  19.             Console.ReadLine();
  20.         }

  也可以直接链式的写下去,代码如下:

Code
  1.         /// <summary>
  2.         /// Task 执行完毕后调用另一个Task(链式写法)
  3.         /// </summary>
  4.         private void Demo4()
  5.         {
  6.             Random r = new Random(DateTime.Now.Second);
  7.             Task<int> t = new Task<int>(() =>
  8.             {
  9.                 int i = 0;
  10.                 for (int v = 0; v < 100; v++)
  11.                     i += r.Next(100);
  12.                 return i;
  13.             });
  14.             Task t2 = t.ContinueWith((Task<int> task) =>
  15.             {
  16.                 Console.WriteLine(task.Result.ToString());
  17.             });
  18.             t2.ContinueWith(task =>
  19.             {
  20.                 Console.WriteLine("这是执行完毕Task1后继续调用Task2,Task2后调用Task3。");
  21.             });
  22.             t.Start();
  23.             Console.ReadLine();
  24.         }

  结论2:Task可以便捷的将几个方法串行执行。

  三、带有父子关系的线程/多线程并行开启

  t带有t1,t2,t3三个子线程,执行t的时候t1,t2,t3可并行处理,t必须等待t1,t2,t3都执行完毕后才能结束。创建子Task时候必须指定参数为AttachedToParent。

Code
  1.         /// <summary>
  2.         /// 带有父子关系的Task集合,[TaskCreationOptions.AttachedToParent]
  3.         ///
  4.         /// 值                说明
  5.         /// None              默认值,此Task会被排入Local Queue中等待执行,采用LIFO模式。
  6.         /// AttachedToParent  建立的Task必须是外围的Task的子Task,也是放入Local Queue,採LIFO模式。
  7.         /// LongRunning       建立的Task不受Thread Pool所管理,直接新增一个Thread来执行此Task,无等待、无排程。
  8.         /// PreferFairness    建立的Task直接放入Global Queue中,採FIFO模式。(比上面的优先级低)
  9.         /// </summary>
  10.         private void Demo5()
  11.         {
  12.             Task<int> t = new Task<int>(() =>
  13.             {
  14.                 Task<int> t1 = new Task<int>(() =>
  15.                 {
  16.                     int i = 0;
  17.                     Random r = new Random(DateTime.Now.Second);
  18.                     for (int v = 0; v < 100; v++)
  19.                         i += r.Next(100);
  20.                     return i;
  21.                 }, TaskCreationOptions.AttachedToParent);
  22.                 Task<int> t2 = new Task<int>(() =>
  23.                 {
  24.                     int i = 0;
  25.                     Random r = new Random(DateTime.Now.Second);
  26.                     for (int v = 0; v < 100; v++)
  27.                         i += r.Next(100);
  28.                     return i;
  29.                 }, TaskCreationOptions.AttachedToParent);
  30.                 Task<int> t3 = new Task<int>(() =>
  31.                 {
  32.                     int i = 0;
  33.                     Random r = new Random(DateTime.Now.Second);
  34.                     for (int v = 0; v < 100; v++)
  35.                         i += r.Next(100);
  36.                     return i;
  37.                 }, TaskCreationOptions.AttachedToParent);
  38.                 t1.Start();
  39.                 t2.Start();
  40.                 t3.Start();
  41.                 return t1.Result + t2.Result + t3.Result;
  42.             });
  43.             t.Start();
  44.             t.Wait();
  45.             Console.WriteLine("这是带有父子关系的Task集合:" + t.Result.ToString());
  46.             Console.ReadLine();
  47.         }

  结论3:多个线程的同时开启在这里也很方便,也不用担心同步等问题。

  四、Task的中断

  这个很复杂,就不多说了,代码中有比较详细的介绍。

Code
  1.         /// <summary>
  2.         /// 中途取消Task执行,Token
  3.         ///
  4.         /// 一是正常结束、二是产生例外、三是透过Cancel机制,这三种情况都会反映在Task.Status属性上
  5.         /// 值                              说明
  6.         /// Created                         Task已经建立,但未呼叫Start。
  7.         /// WaitingForActivation            Task已排入排程,但尚未执行(一般我们建立的Task不会有此状态,只有ContinueWith所产生的Task才会有此状态)。
  8.         /// WaitingToRun                    Task已排入排程,等待执行中。
  9.         /// Running                         Task执行中。
  10.         /// WaitingForChildrenToComplete    Task正等待子Task結束。
  11.         /// RanToCompletion                 Task已经正常执行完毕。
  12.         /// Canceled                        Task已被取消。
  13.         /// Faulted                         Task执行中发生未预期例外。
  14.         ///
  15.         /// 除了Status属性外,Task还提供了另外三个属性来判定Task状态。
  16.         /// 属性            说明
  17.         /// IsCompleted     Task已经正常执行完毕。
  18.         /// IsFaulted       Task执行中法生未预期例外。
  19.         /// IsCanceled      Task已被取消。
  20.         /// </summary>
  21.         private void Demo6()
  22.         {
  23.             CancellationTokenSource cts = new CancellationTokenSource();
  24.             var ctoken = cts.Token;
  25.             Task t1 = new Task(() =>
  26.             {
  27.                 for (int v = 0; v < 10; v++)
  28.                 {
  29.                     if (ctoken.IsCancellationRequested)
  30.                     {
  31.                         //第一种写法
  32.                         //这个会抛出异常
  33.                         ctoken.ThrowIfCancellationRequested();
  34.                         //另一种写法
  35.                         //这个不会返回异常,但是获取不到是否是中断还是执行完毕。
  36.                         //return;
  37.                     }
  38.                     Thread.Sleep(1000);
  39.                     Console.WriteLine(v);
  40.                 }
  41.             }, ctoken);
  42.             t1.Start();
  43.             Thread.Sleep(2000);
  44.             cts.Cancel();
  45.             try
  46.             {
  47.                 t1.Wait();
  48.             }
  49.             catch
  50.             {
  51.                 if (t1.IsCanceled)
  52.                     Console.WriteLine("cancel");
  53.             }
  54.             Console.ReadLine();
  55.             cts.Dispose();
  56.         }

  结论4:中断很复杂,但是对一般逻辑来说,是没有很大必要的。

  五、其他

  这里介绍下另一种写法Task.Factory,以及ContinueWhenAny和ContinueWhenAll两个方法。Task.Factory是静态工厂类,用于对Task提供一些麻烦的支持,这里主要介绍ContinueWhenAny和ContinueWhenAll。

ContinueWhenAll所指定的函式会在传入的所有Tasks结束时执行,只会执行一次。ContinueWhenAny所指定的函式会在传入的Tasks中有任何一个结束时执行,且与ContinueWhenAll相同,只会执行一次。好了,还是看代码:

Code
  1.         /// <summary>
  2.         /// Task.Factory
  3.         /// ContinueWhenAny和ContinueWhenAll
  4.         /// ContinueWhenAll所指定的函式会在传入的所有Tasks结束时执行,只会执行一次。
  5.         /// ContinueWhenAny所指定的函式会在传入的Tasks中有任何一个结束时执行,且与ContinueWhenAll相同,只会执行一次。
  6.         /// </summary>
  7.         private void Demo7()
  8.         {
  9.             Task<int> t1 = Task.Factory.StartNew<int>(() =>
  10.             {
  11.                 int total = 0;
  12.                 for (int i = 0; i < 10; i++)
  13.                     total += i;
  14.                 Thread.Sleep(12000);
  15.                 return total;
  16.             });
  17.             Task<int> t2 = Task.Factory.StartNew<int>(() =>
  18.             {
  19.                 int total = 0;
  20.                 for (int i = 10; i < 20; i++)
  21.                     total += i;
  22.                 Thread.Sleep(10000);
  23.                 return total;
  24.             });
  25.             Task tfinal = Task.Factory.ContinueWhenAny<int>(
  26.                          new Task<int>[] { t1, t2 }, (Task<int> task) =>
  27.                          {
  28.                              if (task.Status == TaskStatus.RanToCompletion)
  29.                              {
  30.                                  Console.WriteLine(task.Result);
  31.                              }
  32.                          });
  33.             Console.ReadLine();
  34.         }

  结论5:ContinueWhenAny和ContinueWhenAll对特定条件执行,还是有些用处的。

  好了,这篇文章算是完结了,4.0中的并行和线程确实简单了很多,使用起来也很方便,为了性能的提升还是要适当的使用下。

目录
相关文章
|
监控 Cloud Native 测试技术
.NET技术深度解析:现代企业级开发指南
每日激励:“不要一直责怪过去的自己,他曾经站在雾里也很迷茫”。我是蒋星熠Jaxonic,一名在代码宇宙中探索的极客旅人。从.NET Framework到.NET 8,我深耕跨平台、高性能、云原生开发,践行领域驱动设计与微服务架构,用代码书写技术诗篇。分享架构演进、性能优化与AI融合前沿,助力开发者在二进制星河中逐光前行。关注我,共探技术无限可能!
.NET技术深度解析:现代企业级开发指南
|
SQL 小程序 API
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
734 0
|
开发框架 算法 .NET
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
375 6
|
开发框架 Cloud Native .NET
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
428 6
|
开发框架 安全 .NET
在数字化时代,.NET 技术凭借跨平台兼容性、丰富的开发工具和框架、高效的性能及强大的安全稳定性,成为软件开发的重要支柱
在数字化时代,.NET 技术凭借跨平台兼容性、丰富的开发工具和框架、高效的性能及强大的安全稳定性,成为软件开发的重要支柱。它不仅加速了应用开发进程,提升了开发质量和可靠性,还促进了创新和业务发展,培养了专业人才和技术社区,为软件开发和数字化转型做出了重要贡献。
478 5
|
传感器 人工智能 供应链
.NET开发技术在数字化时代的创新作用,从高效的开发环境、强大的性能表现、丰富的库和框架资源等方面揭示了其关键优势。
本文深入探讨了.NET开发技术在数字化时代的创新作用,从高效的开发环境、强大的性能表现、丰富的库和框架资源等方面揭示了其关键优势。通过企业级应用、Web应用及移动应用的创新案例,展示了.NET在各领域的广泛应用和巨大潜力。展望未来,.NET将与新兴技术深度融合,拓展跨平台开发,推动云原生应用发展,持续创新。
292 4
|
开发框架 .NET C#
.NET 技术凭借高效开发环境、强大框架支持及跨平台特性,在软件开发中占据重要地位
.NET 技术凭借高效开发环境、强大框架支持及跨平台特性,在软件开发中占据重要地位。从企业应用到电子商务,再到移动开发,.NET 均展现出卓越性能,助力开发者提升效率与项目质量,推动行业持续发展。
543 4
|
机器学习/深度学习 人工智能 Cloud Native
在数字化时代,.NET 技术凭借其跨平台兼容性、丰富的类库和工具集以及卓越的性能与效率,成为软件开发的重要平台
在数字化时代,.NET 技术凭借其跨平台兼容性、丰富的类库和工具集以及卓越的性能与效率,成为软件开发的重要平台。本文深入解析 .NET 的核心优势,探讨其在企业级应用、Web 开发及移动应用等领域的应用案例,并展望未来在人工智能、云原生等方面的发展趋势。
559 3
|
敏捷开发 缓存 中间件
.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素
本文深入探讨了.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素,并通过企业级应用和Web应用开发的实践案例,展示了如何在实际项目中应用这些模式,旨在为开发者提供有益的参考和指导。
274 3
|
开发框架 安全 Java
.NET技术的独特魅力与优势,涵盖高效的开发体验、强大的性能表现、高度的可扩展性及丰富的生态系统等方面,展示了其在软件开发领域的核心竞争力
本文深入探讨了.NET技术的独特魅力与优势,涵盖高效的开发体验、强大的性能表现、高度的可扩展性及丰富的生态系统等方面,展示了其在软件开发领域的核心竞争力。.NET不仅支持跨平台开发,具备出色的安全性和稳定性,还能与多种技术无缝集成,为企业级应用提供全面支持。
683 3

热门文章

最新文章