威尼斯人线上娱乐

走进异步编制程序的社会风气,剖析异步方法

18 4月 , 2019  

走进异步编制程序的世界 – 剖析异步方法(下)

 

[C#] 走进异步编制程序的社会风气,

走进异步编制程序的世界 – 剖析异步方法(下)

 

义务概述

线程(Thread)是创立并发的平底工具,因而有一定的局限性(不易得到重临值(必须通过创立共享域);分外的破获和拍卖也麻烦;同时线程实行达成后不恐怕再一次开启该线程),那么些局限性会降低质量同时影响并发性的达成(不轻松组合较小的产出操作完结较大的面世操作,会追加手工同步处理(加锁,发送时限信号)的依靠,轻便并发难点)。

线程池的(ThreadPool)QueueUserWorkItem艺术很容发起三次异步的测算范围操作。但以此手艺同样具备大多限制,最大的主题材料是未曾内建的建制让您驾驭操作在怎么样时候做到,也从未编写制定在操作实现时收获重临值。

Task类能够化解上述全数的主题材料。

任务(Task)意味着贰个通过或不经过线程达成的出现操作,任务是可结合的,使用延续(continuation)可将它们串联在1块,它们能够使用线程池收缩运行延迟,可选用回调方法幸免四个线程同时等待I/O密集操作。

 

  多谢大家的支撑,这是今日发表《走进异步编制程序的世界 –
剖析异步方法(上)》的增补篇。

 

走进异步编程的世界 – 剖析异步方法(下)

 

  感激大家的支撑,这是后日发表《走进异步编制程序的世界 –
剖析异步方法(上)》的补偿篇。

 

基本功职责(Task)

微软在.NET 4.0 引入任务(Task)的定义。通过System.Threading.Tasks命名空间应用任务。它是在ThreadPool的基本功上拓展打包的。Task暗中认可都是应用池化线程,它们都是后台线程走进异步编制程序的社会风气,剖析异步方法。,那象征主线程停止时其余任务也会随着告1段落。

开发银行三个任务有二种艺术,如以下示例:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Console.WriteLine("主线程Id:{0}", Thread.CurrentThread.ManagedThreadId);
 6             int workerThreadsCount, completionPortThreadsCount;
 7             ThreadPool.GetAvailableThreads(out workerThreadsCount, out completionPortThreadsCount);
 8             Console.WriteLine("剩余工作线程数:{0},剩余IO线程数{1}", workerThreadsCount, completionPortThreadsCount);
 9             //第一种:实例化方式Start启动
10             {
11                 Task task = new Task(() =>
12                 {
13                     Test("one-ok");
14                 });
15                 task.Start();
16             }
17             //第二种:通过Task类静态方法Run方式进行启动
18             {
19                 Task.Run(() =>
20                 {
21                     Test("two-ok");
22                 });
23             }
24             //第三种:通过TaskFactory的StartNew方法启动
25             {
26                 TaskFactory taskFactory = new TaskFactory();
27                 taskFactory.StartNew(() =>
28                 {
29                     Test("three-ok");
30                 });
31             }
32             //第四种:.通过Task.Factory进行启动
33             {
34                 Task taskStarNew = Task.Factory.StartNew(() =>
35                 {
36                     Test("four-ok");
37                 });
38             }
39             //第五种:通过Task对象的RunSynchronously方法启动(同步,由主线程执行,会卡主线程)
40             {
41                 Task taskRunSync = new Task(() =>
42                 {
43                     Console.WriteLine("线程Id:{0},执行方法:five-ok", Thread.CurrentThread.ManagedThreadId);
44                 });
45                 taskRunSync.RunSynchronously();
46             }
47             Thread.Sleep(1000);
48             ThreadPool.GetAvailableThreads(out workerThreadsCount, out completionPortThreadsCount);
49             Console.WriteLine("剩余工作线程数:{0},剩余IO线程数{1}", workerThreadsCount, completionPortThreadsCount);
50             Console.ReadKey();
51         }
52         static void Test(string o)
53         {
54             Thread.Sleep(2000);
55             Console.WriteLine("线程Id:{0},执行方法:{1}", Thread.CurrentThread.ManagedThreadId, o);
56         }
57         /*
58          * 作者:Jonins
59          * 出处:http://www.cnblogs.com/jonins/
60          */
61     }

实践结果:

威尼斯人线上娱乐 1

地方示例中除去使用RunSynchronously方法运营的是联合签名任务(由启用的线程试行任务)外,其余两种形式之中都由线程池内的劳引力线程处理。

说明

一.事实上Task.Factory类型自个儿便是TaskFactory(职分工厂),而Task.Run(在.NET肆.5引进,四.0版本调用的是后世)是Task.Factory.StartNew的简写法,是后世的重载版本,越来越灵活轻易些。

贰.调用静态Run方法会自动创造Task对象并立即调用Start

三.如Task.Run等方式运维职分并未调用Start,因为它创设的是“热”义务,相反“冷”职务的创制是经过Task构造函数。

 

目录

  • 10分处理
  • 在调用方法中联合等待职务
  • 在异步方法中异步等待义务
  • Task.Delay()
    暂停实施

  

  多谢大家的支撑,那是前天发布《走进异步编制程序的世界 –
剖析异步方法(上)》的增加补充篇。

 

目录

  • 老大处理
  • 在调用方法中一块等待职责
  • 在异步方法中异步等待职务
  • Task.Delay()
    暂停试行

  

返回值(Task<TResult>)&状态(Status)

Task有二个泛型子类Task<TResult>,它同意职分再次回到3个值。调用Task.Run,传入2个Func<Tresult>代理或包容的拉姆da表明式,然后查询Result属性获得结果。假定任务未有到位,那么访问Result属性会阻塞当前线程,直至职务到位

1     public static Task<TResult> Run<TResult>(Func<TResult> function);

而职分的Status本性可用于追踪职分的履市价况,如下所示:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Task<int> task = Task.Run(() =>
 6             {
 7                 int total = 0;
 8                 for (int i = 0; i <= 100; i++)
 9                 {
10                     total += i;
11                 }
12                 Thread.Sleep(2000);
13                 return total;
14             });
15             Console.WriteLine("任务状态:{0}",task.Status);
16             Thread.Sleep(1000);
17             Console.WriteLine("任务状态:{0}", task.Status);
18             int totalCount = task.Result;//如果任务没有完成,则阻塞
19             Console.WriteLine("任务状态:{0}", task.Status);
20             Console.WriteLine("总数为:{0}",totalCount);
21             Console.ReadKey();
22         }
23     }

实行如下:

 威尼斯人线上娱乐 2

Reulst属性内部会调用Wait(等待);

任务的Status属性是一个TaskStatus枚举类型:

1  public TaskStatus Status { get; }

表达如下:

枚举值 说明
Canceled

任务已通过对其自身的 CancellationToken 引发 OperationCanceledException 对取消进行了确认,此时该标记处于已发送信号状态;

或者在该任务开始执行之前,已向该任务的 CancellationToken 发出了信号。

Created 该任务已初始化,但尚未被计划。
Faulted 由于未处理异常的原因而完成的任务。
RanToCompletion 已完成执行的任务。
Running 任务正在运行,尚未完成。
WaitingForActivation 该任务正在等待 .NET Framework 基础结构在内部将其激活并进行计划。
WaitingForChildrenToComplete 该任务已完成执行,正在隐式等待附加的子任务完成。
WaitingToRun 该任务已被计划执行,但尚未开始执行。

 

1、分外处理

  await 表明式也能够动用 try…catch…finally 结构。

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             var t = DoExceptionAsync();
 6             t.Wait();
 7 
 8             Console.WriteLine($"{nameof(t.Status)}: {t.Status}");   //任务状态
 9             Console.WriteLine($"{nameof(t.IsCompleted)}: {t.IsCompleted}");     //任务完成状态标识
10             Console.WriteLine($"{nameof(t.IsFaulted)}: {t.IsFaulted}");     //任务是否有未处理的异常标识
11 
12             Console.Read();
13         }
14 
15         /// <summary>
16         /// 异常操作
17         /// </summary>
18         /// <returns></returns>
19         private static async Task DoExceptionAsync()
20         {
21             try
22             {
23                 await Task.Run(() => { throw new Exception(); });
24             }
25             catch (Exception)
26             {
27                 Console.WriteLine($"{nameof(DoExceptionAsync)} 出现异常!");
28             }
29         }
30     }

威尼斯人线上娱乐 3

图1-1

  【分析】await
表达式位于 try
块中,按壹般的秘诀处理非凡。不过,为何图中的状态(Status)、是还是不是产生标记(IsCompleted)和是还是不是失利标志(IsFaulted)分别突显:运营成功(RanToCompletion)
、已成功(True) 和 未退步(False)
呢?因为:义务未有被打消,并且12分都早已处理实现!

 

目录

  • 丰盛处理
  • 在调用方法中同步等待职分
  • 在异步方法中异步等待任务
  • Task.Delay() 暂停施行

  

壹、非常处理

  await 表明式也得以选择 try…catch…finally 结构。

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             var t = DoExceptionAsync();
 6             t.Wait();
 7 
 8             Console.WriteLine($"{nameof(t.Status)}: {t.Status}");   //任务状态
 9             Console.WriteLine($"{nameof(t.IsCompleted)}: {t.IsCompleted}");     //任务完成状态标识
10             Console.WriteLine($"{nameof(t.IsFaulted)}: {t.IsFaulted}");     //任务是否有未处理的异常标识
11 
12             Console.Read();
13         }
14 
15         /// <summary>
16         /// 异常操作
17         /// </summary>
18         /// <returns></returns>
19         private static async Task DoExceptionAsync()
20         {
21             try
22             {
23                 await Task.Run(() => { throw new Exception(); });
24             }
25             catch (Exception)
26             {
27                 Console.WriteLine($"{nameof(DoExceptionAsync)} 出现异常!");
28             }
29         }
30     }

威尼斯人线上娱乐 4

图1-1

  【分析】await
表明式位于 try
块中,按一般的措施处理十分。不过,为啥图中的状态(Status)、是还是不是到位标志(IsCompleted)和是不是失利标志(IsFaulted)分别显示:运营实现(RanToCompletion)
、已成功(True) 和 未退步(False)
呢?因为:职务未有被注销,并且十一分都早已处理完了!

 

任务集合再次回到值(WhenAll&WhenAny)

 Task中有非凡有利的对相互运转的天职集合获取再次回到值的艺术,比如WhenAllWhenAny

贰、在调用方法中齐声等待职责

  调用方法大概在某个时间点上必要拭目以俟某些特殊的 Task
对象完毕,才施行后边的代码。此时,能够利用实例方法 Wait 。

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             var t = CountCharactersAsync("http://www.cnblogs.com/liqingwen/");
 6 
 7             t.Wait();   //等待任务结束
 8             Console.WriteLine($"Result is {t.Result}");
 9 
10             Console.Read();
11         }
12 
13         /// <summary>
14         /// 统计字符数量
15         /// </summary>
16         /// <param name="address"></param>
17         /// <returns></returns>
18         private static async Task<int> CountCharactersAsync(string address)
19         {
20             var result = await Task.Run(() => new WebClient().DownloadStringTaskAsync(address));
21             return result.Length;
22         }
23     }

威尼斯人线上娱乐 5

图2-1

 

  Wait() 适合用于单壹 Task 对象,借使想操作一组对象,可利用 Task
的五个静态方法 WaitAll() 和 WaitAny() 。

 1     internal class Program
 2     {
 3         private static int time = 0;
 4         private static void Main(string[] args)
 5         {
 6             var t1 = GetRandomAsync(1);
 7             var t2 = GetRandomAsync(2);
 8 
 9             //IsCompleted 任务完成标识
10             Console.WriteLine($"t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");    
11             Console.WriteLine($"t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
12 
13             Console.Read();
14         }
15 
16         /// <summary>
17         /// 获取一个随机数
18         /// </summary>
19         /// <param name="id"></param>
20         /// <returns></returns>
21         private static async Task<int> GetRandomAsync(int id)
22         {
23             var num = await Task.Run(() =>
24             {
25                 time++;
26                 Thread.Sleep(time * 100);
27                 return new Random().Next();
28             });
29 
30             Console.WriteLine($"{id} 已经调用完成");
31             return num;
32         }
33     }

威尼斯人线上娱乐 6

图二-2 多个职责的 IsCompleted 属性都呈现未到位

 

  现在,在 Main() 方法中新增加两行代码(陆 和 柒 两行),尝试调用
WaitAll() 方法。

 1         private static void Main(string[] args)
 2         {
 3             var t1 = GetRandomAsync(1);
 4             var t2 = GetRandomAsync(2);
 5 
 6             Task<int>[] tasks = new Task<int>[] { t1, t2 };
 7             Task.WaitAll(tasks);    //等待任务全部完成,才继续执行
 8 
 9             //IsCompleted 任务完成标识
10             Console.WriteLine($"t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");    
11             Console.WriteLine($"t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
12 
13             Console.Read();
14         }

威尼斯人线上娱乐 7

图二-三 三个职责的 IsCompleted 属性都体现 True

 

  未来,再一次将第 7 行更动一下,调用 WaitAny() 方法尝试。 

 1         private static void Main(string[] args)
 2         {
 3             var t1 = GetRandomAsync(1);
 4             var t2 = GetRandomAsync(2);
 5 
 6             Task<int>[] tasks = new Task<int>[] { t1, t2 };
 7             Task.WaitAny(tasks);    //等待任一 Task 完成,才继续执行
 8 
 9             //IsCompleted 任务完成标识
10             Console.WriteLine($"t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");    
11             Console.WriteLine($"t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
12 
13             Console.Read();
14         }

威尼斯人线上娱乐 8

图贰-4 有一个任务的 IsCompleted 属性显示 True (实现) 就继续试行

 

1、非常处理

  await 表达式也足以动用 try…catch…finally 结构。

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             var t = DoExceptionAsync();
 6             t.Wait();
 7 
 8             Console.WriteLine($"{nameof(t.Status)}: {t.Status}");   //任务状态
 9             Console.WriteLine($"{nameof(t.IsCompleted)}: {t.IsCompleted}");     //任务完成状态标识
10             Console.WriteLine($"{nameof(t.IsFaulted)}: {t.IsFaulted}");     //任务是否有未处理的异常标识
11 
12             Console.Read();
13         }
14 
15         /// <summary>
16         /// 异常操作
17         /// </summary>
18         /// <returns></returns>
19         private static async Task DoExceptionAsync()
20         {
21             try
22             {
23                 await Task.Run(() => { throw new Exception(); });
24             }
25             catch (Exception)
26             {
27                 Console.WriteLine($"{nameof(DoExceptionAsync)} 出现异常!");
28             }
29         }
30     }

图1-1

  【分析】await 表明式位于 try
块中,按1般的措施处理分外。不过,为何图中的状态(Status)、是不是形成标志(IsCompleted)和是或不是战败标志(IsFaulted)分别展现:运营成功(RanToCompletion)
、已成功(True) 和 未失利(False)
呢?因为:职责未有被打消,并且越发都早已处理到位!

 

二、在调用方法中联合等待职责

  调用方法也许在某些时刻点上急需等待有些特殊的 Task
对象实现,才施行前边的代码。此时,能够选取实例方法 Wait 。

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             var t = CountCharactersAsync("http://www.cnblogs.com/liqingwen/");
 6 
 7             t.Wait();   //等待任务结束
 8             Console.WriteLine($"Result is {t.Result}");
 9 
10             Console.Read();
11         }
12 
13         /// <summary>
14         /// 统计字符数量
15         /// </summary>
16         /// <param name="address"></param>
17         /// <returns></returns>
18         private static async Task<int> CountCharactersAsync(string address)
19         {
20             var result = await Task.Run(() => new WebClient().DownloadStringTaskAsync(address));
21             return result.Length;
22         }
23     }

威尼斯人线上娱乐 9

图2-1

 

  Wait() 适合用来单一 Task 对象,倘使想操作一组对象,可应用 Task
的五个静态方法 WaitAll() 和 WaitAny() 。

 1     internal class Program
 2     {
 3         private static int time = 0;
 4         private static void Main(string[] args)
 5         {
 6             var t1 = GetRandomAsync(1);
 7             var t2 = GetRandomAsync(2);
 8 
 9             //IsCompleted 任务完成标识
10             Console.WriteLine($"t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");    
11             Console.WriteLine($"t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
12 
13             Console.Read();
14         }
15 
16         /// <summary>
17         /// 获取一个随机数
18         /// </summary>
19         /// <param name="id"></param>
20         /// <returns></returns>
21         private static async Task<int> GetRandomAsync(int id)
22         {
23             var num = await Task.Run(() =>
24             {
25                 time++;
26                 Thread.Sleep(time * 100);
27                 return new Random().Next();
28             });
29 
30             Console.WriteLine($"{id} 已经调用完成");
31             return num;
32         }
33     }

威尼斯人线上娱乐 10

图贰-二 五个任务的 IsCompleted 属性都展现未产生

 

  未来,在 Main() 方法中新添两行代码(陆 和 7 两行),尝试调用
WaitAll() 方法。

 1         private static void Main(string[] args)
 2         {
 3             var t1 = GetRandomAsync(1);
 4             var t2 = GetRandomAsync(2);
 5 
 6             Task<int>[] tasks = new Task<int>[] { t1, t2 };
 7             Task.WaitAll(tasks);    //等待任务全部完成,才继续执行
 8 
 9             //IsCompleted 任务完成标识
10             Console.WriteLine($"t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");    
11             Console.WriteLine($"t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
12 
13             Console.Read();
14         }

威尼斯人线上娱乐 11

图二-三 四个义务的 IsCompleted 属性都呈现 True

 

  以后,再度将第 7 行改变一下,调用 WaitAny() 方法尝试。 

 1         private static void Main(string[] args)
 2         {
 3             var t1 = GetRandomAsync(1);
 4             var t2 = GetRandomAsync(2);
 5 
 6             Task<int>[] tasks = new Task<int>[] { t1, t2 };
 7             Task.WaitAny(tasks);    //等待任一 Task 完成,才继续执行
 8 
 9             //IsCompleted 任务完成标识
10             Console.WriteLine($"t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");    
11             Console.WriteLine($"t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
12 
13             Console.Read();
14         }

威尼斯人线上娱乐 12

图二-四 有四个职务的 IsCompleted 属性显示 True (达成) 就继续施行

 

1.WhenAll

WhenAll:伺机提供的具备 Task 对象达成实践进度(全部任务总体成功)。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             List<Task<int>> taskList = new List<Task<int>>();//声明一个任务集合
 6             TaskFactory taskFactory = new TaskFactory();
 7             for (int i = 0; i < 5; i++)
 8             {
 9                 int total = i;
10                 Task<int> task = taskFactory.StartNew(() => Test(total));
11                 taskList.Add(task);//将任务放进集合中
12             }
13             Console.WriteLine("主线程Id:{0},继续执行A.....", Thread.CurrentThread.ManagedThreadId);
14             Task<int[]> taskReulstList = Task.WhenAll(taskList);//创建一个任务,该任务将集合中的所有 Task 对象都完成时完成
15             for (int i = 0; i < taskReulstList.Result.Length; i++)//这里调用了Result,所以会阻塞线程,等待集合内所有任务全部完成
16             {
17                 Console.WriteLine("返回值:{0}", taskReulstList.Result[i]);//遍历任务集合内Task返回的值
18             }
19             Console.WriteLine("主线程Id:{0},继续执行B.....", Thread.CurrentThread.ManagedThreadId);
20             Console.ReadKey();
21         }
22         private static int Test(int o)
23         {
24             Console.WriteLine("线程Id:{0},Task执行成功,参数为:{1}", Thread.CurrentThread.ManagedThreadId, o);
25             Thread.Sleep(500 * o);
26             return o;
27         }
28     }

执行结果:

威尼斯人线上娱乐 13

叁、在异步方法中异步等待职责

  上节说的是何等行使 WaitAll() 和 WaitAny() 同步地等待 Task
完成。此次大家利用 Task.WhenAll() 和 Task.WhenAny()
 在异步方法中异步等待职务。

 1     internal class Program
 2     {
 3         private static int time = 0;
 4 
 5         private static void Main(string[] args)
 6         {
 7             var t = GetRandomAsync();
 8 
 9             Console.WriteLine($"t.{nameof(t.IsCompleted)}: {t.IsCompleted}");
10             Console.WriteLine($"Result: {t.Result}");
11 
12             Console.Read();
13         }
14 
15         /// <summary>
16         /// 获取一个随机数
17         /// </summary>
18         /// <param name="id"></param>
19         /// <returns></returns>
20         private static async Task<int> GetRandomAsync()
21         {
22             time++;
23             var t1 = Task.Run(() =>
24             {
25                 Thread.Sleep(time * 100);
26                 return new Random().Next();
27             });
28 
29             time++;
30             var t2 = Task.Run(() =>
31             {
32                 Thread.Sleep(time * 100);
33                 return new Random().Next();
34             });
35 
36             //异步等待集合内的 Task 都完成,才进行下一步操作
37             await Task.WhenAll(new List<Task<int>>() { t1, t2 });
38 
39             Console.WriteLine($"    t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");
40             Console.WriteLine($"    t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
41 
42             return t1.Result + t2.Result;
43         }
44     }

威尼斯人线上娱乐 14

图3-1 调用 WhenAll()  方法

  【注意】WhenAll() 异步等待集合内的
Task 都做到,不会占领主线程的时刻。

 

   今后,大家把 GetRandomAsync() 方法内的 WhenAll() 方法替换到WhenAny(),并且增大学一年级下线程挂起时间,最后改动如下:

 1         private static async Task<int> GetRandomAsync()
 2         {
 3             time++;
 4             var t1 = Task.Run(() =>
 5             {
 6                 Thread.Sleep(time * 100);
 7                 return new Random().Next();
 8             });
 9 
10             time++;
11             var t2 = Task.Run(() =>
12             {
13                 Thread.Sleep(time * 500);   //这里由 100 改为 500,不然看不到效果
14                 return new Random().Next();
15             });
16 
17             //异步等待集合内的 Task 都完成,才进行下一步操作
18             //await Task.WhenAll(new List<Task<int>>() { t1, t2 });
19             await Task.WhenAny(new List<Task<int>>() { t1, t2 });
20 
21             Console.WriteLine($"    t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");
22             Console.WriteLine($"    t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
23 
24             return t1.Result + t2.Result;
25         }

威尼斯人线上娱乐 15

图3-2 调用 WhenAny() 方法

 

二、在调用方法中三只等待任务

  调用方法大概在有个别时刻点上需求拭目以俟有些特殊的 Task
对象完毕,才实践前面包车型地铁代码。此时,能够动用实例方法 Wait 。

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             var t = CountCharactersAsync("http://www.cnblogs.com/liqingwen/");
 6 
 7             t.Wait();   //等待任务结束
 8             Console.WriteLine($"Result is {t.Result}");
 9 
10             Console.Read();
11         }
12 
13         /// <summary>
14         /// 统计字符数量
15         /// </summary>
16         /// <param name="address"></param>
17         /// <returns></returns>
18         private static async Task<int> CountCharactersAsync(string address)
19         {
20             var result = await Task.Run(() => new WebClient().DownloadStringTaskAsync(address));
21             return result.Length;
22         }
23     }

威尼斯人线上娱乐 16

图2-1

 

  Wait() 适合用来单壹 Task 对象,假诺想操作1组对象,可使用 Task
的五个静态方法 WaitAll() 和 WaitAny() 。

 1     internal class Program
 2     {
 3         private static int time = 0;
 4         private static void Main(string[] args)
 5         {
 6             var t1 = GetRandomAsync(1);
 7             var t2 = GetRandomAsync(2);
 8 
 9             //IsCompleted 任务完成标识
10             Console.WriteLine($"t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");    
11             Console.WriteLine($"t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
12 
13             Console.Read();
14         }
15 
16         /// <summary>
17         /// 获取一个随机数
18         /// </summary>
19         /// <param name="id"></param>
20         /// <returns></returns>
21         private static async Task<int> GetRandomAsync(int id)
22         {
23             var num = await Task.Run(() =>
24             {
25                 time++;
26                 Thread.Sleep(time * 100);
27                 return new Random().Next();
28             });
29 
30             Console.WriteLine($"{id} 已经调用完成");
31             return num;
32         }
33     }

图二-二 四个职务的 IsCompleted 属性都突显未到位

 

  现在,在 Main() 方法中新添两行代码(六 和 7 两行),尝试调用
WaitAll() 方法。

 1         private static void Main(string[] args)
 2         {
 3             var t1 = GetRandomAsync(1);
 4             var t2 = GetRandomAsync(2);
 5 
 6             Task<int>[] tasks = new Task<int>[] { t1, t2 };
 7             Task.WaitAll(tasks);    //等待任务全部完成,才继续执行
 8 
 9             //IsCompleted 任务完成标识
10             Console.WriteLine($"t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");    
11             Console.WriteLine($"t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
12 
13             Console.Read();
14         }

威尼斯人线上娱乐 17

图2-三 几个职分的 IsCompleted 属性都来得 True

 

  以往,再度将第 7 行改造一下,调用 WaitAny() 方法尝试。 

 1         private static void Main(string[] args)
 2         {
 3             var t1 = GetRandomAsync(1);
 4             var t2 = GetRandomAsync(2);
 5 
 6             Task<int>[] tasks = new Task<int>[] { t1, t2 };
 7             Task.WaitAny(tasks);    //等待任一 Task 完成,才继续执行
 8 
 9             //IsCompleted 任务完成标识
10             Console.WriteLine($"t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");    
11             Console.WriteLine($"t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
12 
13             Console.Read();
14         }

图2-肆 有八个职分的 IsCompleted 属性展现 True (完结) 就继续实施

 

3、在异步方法中异步等待任务

  上节说的是怎么使用 WaitAll() 和 WaitAny() 同步地守候 Task
完毕。这一次大家使用 Task.WhenAll() 和 Task.WhenAny()
 在异步方法中异步等待职务。

 1     internal class Program
 2     {
 3         private static int time = 0;
 4 
 5         private static void Main(string[] args)
 6         {
 7             var t = GetRandomAsync();
 8 
 9             Console.WriteLine($"t.{nameof(t.IsCompleted)}: {t.IsCompleted}");
10             Console.WriteLine($"Result: {t.Result}");
11 
12             Console.Read();
13         }
14 
15         /// <summary>
16         /// 获取一个随机数
17         /// </summary>
18         /// <param name="id"></param>
19         /// <returns></returns>
20         private static async Task<int> GetRandomAsync()
21         {
22             time++;
23             var t1 = Task.Run(() =>
24             {
25                 Thread.Sleep(time * 100);
26                 return new Random().Next();
27             });
28 
29             time++;
30             var t2 = Task.Run(() =>
31             {
32                 Thread.Sleep(time * 100);
33                 return new Random().Next();
34             });
35 
36             //异步等待集合内的 Task 都完成,才进行下一步操作
37             await Task.WhenAll(new List<Task<int>>() { t1, t2 });
38 
39             Console.WriteLine($"    t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");
40             Console.WriteLine($"    t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
41 
42             return t1.Result + t2.Result;
43         }
44     }

威尼斯人线上娱乐 18

图3-1 调用 WhenAll()  方法

  【注意】WhenAll() 异步等待集合内的
Task 都做到,不会据有主线程的岁月。

 

   今后,我们把 GetRandomAsync() 方法内的 WhenAll() 方法替换成WhenAny(),并且增大一下线程挂起时间,最后改换如下:

 1         private static async Task<int> GetRandomAsync()
 2         {
 3             time++;
 4             var t1 = Task.Run(() =>
 5             {
 6                 Thread.Sleep(time * 100);
 7                 return new Random().Next();
 8             });
 9 
10             time++;
11             var t2 = Task.Run(() =>
12             {
13                 Thread.Sleep(time * 500);   //这里由 100 改为 500,不然看不到效果
14                 return new Random().Next();
15             });
16 
17             //异步等待集合内的 Task 都完成,才进行下一步操作
18             //await Task.WhenAll(new List<Task<int>>() { t1, t2 });
19             await Task.WhenAny(new List<Task<int>>() { t1, t2 });
20 
21             Console.WriteLine($"    t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");
22             Console.WriteLine($"    t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
23 
24             return t1.Result + t2.Result;
25         }

威尼斯人线上娱乐 19

图3-2 调用 WhenAny() 方法

 

2.WhenAny

WhenAny:等待提供的任一 Task 对象实现实行进度(只要有2个任务达成)。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             List<Task<int>> taskList = new List<Task<int>>();//声明一个任务集合
 6             TaskFactory taskFactory = new TaskFactory();
 7             for (int i = 0; i < 5; i++)
 8             {
 9                 int total = i;
10                 Task<int> task = taskFactory.StartNew(() => Test(total));
11                 taskList.Add(task);//将任务放进集合中
12             }
13             Console.WriteLine("主线程Id:{0},继续执行A.....", Thread.CurrentThread.ManagedThreadId);
14             Task<Task<int>> taskReulstList = Task.WhenAny(taskList);//创建一个任务,该任务将在集合中的任意 Task 对象完成时完成
15             Console.WriteLine("返回值:{0}", taskReulstList.Result.Result);//得到任务集合内最先完成的任务的返回值
16             Console.WriteLine("主线程Id:{0},继续执行B.....", Thread.CurrentThread.ManagedThreadId);
17             Console.ReadKey();
18         }
19         private static int Test(int o)
20         {
21             Console.WriteLine("线程Id:{0},Task执行成功,参数为:{1}", Thread.CurrentThread.ManagedThreadId, o);
22             Thread.Sleep(500 * o);
23             return o;
24         }
25     }

试行结果(那里再次回到值断定会是0,因为休眠最短):

威尼斯人线上娱乐 20

 

肆、Task.Delay() 暂停实践

  Task.Delay() 方法会创设多个 Task
对象,该目的将暂停其在线程中的处理,并在确按期期过后产生。和
Thread.Sleep 差异的是,它不会阻塞线程,意味着线程能够继续处理别的工作。

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             Console.WriteLine($"{nameof(Main)} - start.");
 6             DoAsync();
 7             Console.WriteLine($"{nameof(Main)} - end.");
 8 
 9             Console.Read();
10         }
11 
12         private static async void DoAsync()
13         {
14             Console.WriteLine($"    {nameof(DoAsync)} - start.");
15 
16             await Task.Delay(500);
17 
18             Console.WriteLine($"    {nameof(DoAsync)} - end.");
19         }
20     }

威尼斯人线上娱乐 21

图4-1

 

3、在异步方法中异步等待义务

  上节说的是怎么样运用 WaitAll() 和 WaitAny() 同步地伺机 Task
完结。这一次大家应用 Task.WhenAll() 和 Task.WhenAny()
 在异步方法中异步等待职务。

 1     internal class Program
 2     {
 3         private static int time = 0;
 4 
 5         private static void Main(string[] args)
 6         {
 7             var t = GetRandomAsync();
 8 
 9             Console.WriteLine($"t.{nameof(t.IsCompleted)}: {t.IsCompleted}");
10             Console.WriteLine($"Result: {t.Result}");
11 
12             Console.Read();
13         }
14 
15         /// <summary>
16         /// 获取一个随机数
17         /// </summary>
18         /// <param name="id"></param>
19         /// <returns></returns>
20         private static async Task<int> GetRandomAsync()
21         {
22             time++;
23             var t1 = Task.Run(() =>
24             {
25                 Thread.Sleep(time * 100);
26                 return new Random().Next();
27             });
28 
29             time++;
30             var t2 = Task.Run(() =>
31             {
32                 Thread.Sleep(time * 100);
33                 return new Random().Next();
34             });
35 
36             //异步等待集合内的 Task 都完成,才进行下一步操作
37             await Task.WhenAll(new List<Task<int>>() { t1, t2 });
38 
39             Console.WriteLine($"    t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");
40             Console.WriteLine($"    t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
41 
42             return t1.Result + t2.Result;
43         }
44     }

图3-1 调用 WhenAll()  方法

  【注意】WhenAll() 异步等待集合内的 Task
都完成,不会侵夺主线程的时日。

 

   现在,我们把 GetRandomAsync() 方法内的 WhenAll() 方法替换到WhenAny(),并且增大一下线程挂起时间,最终改换如下:

 1         private static async Task<int> GetRandomAsync()
 2         {
 3             time++;
 4             var t1 = Task.Run(() =>
 5             {
 6                 Thread.Sleep(time * 100);
 7                 return new Random().Next();
 8             });
 9 
10             time++;
11             var t2 = Task.Run(() =>
12             {
13                 Thread.Sleep(time * 500);   //这里由 100 改为 500,不然看不到效果
14                 return new Random().Next();
15             });
16 
17             //异步等待集合内的 Task 都完成,才进行下一步操作
18             //await Task.WhenAll(new List<Task<int>>() { t1, t2 });
19             await Task.WhenAny(new List<Task<int>>() { t1, t2 });
20 
21             Console.WriteLine($"    t1.{nameof(t1.IsCompleted)}: {t1.IsCompleted}");
22             Console.WriteLine($"    t2.{nameof(t2.IsCompleted)}: {t2.IsCompleted}");
23 
24             return t1.Result + t2.Result;
25         }

图3-2 调用 WhenAny() 方法

 

肆、Task.Delay() 暂停实施

  Task.Delay() 方法会创制贰个 Task
对象,该目的将中止其在线程中的处理,并在肯定期间过后实现。和
Thread.Sleep 分歧的是,它不会阻塞线程,意味着线程能够继续处理别的工作。

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             Console.WriteLine($"{nameof(Main)} - start.");
 6             DoAsync();
 7             Console.WriteLine($"{nameof(Main)} - end.");
 8 
 9             Console.Read();
10         }
11 
12         private static async void DoAsync()
13         {
14             Console.WriteLine($"    {nameof(DoAsync)} - start.");
15 
16             await Task.Delay(500);
17 
18             Console.WriteLine($"    {nameof(DoAsync)} - end.");
19         }
20     }

威尼斯人线上娱乐 22

图4-1

 

等待(Wait)&实践措施(TaskCreationOptions)

传送门

  入门:《始于接触 async/await
异步编制程序》

  上篇:《走进异步编制程序的社会风气 –
剖析异步方法(上)》

  下篇:《走进异步编制程序的世界 – 在 GUI
中推行异步操作》

 


 【原来的书文链接】

【参考】《Illustrated C# 2012》

四、Task.Delay() 暂停实践

  Task.Delay() 方法会创设一个 Task
对象,该指标将暂停其在线程中的处理,并在必然时间现在完毕。和
Thread.Sleep 不相同的是,它不会堵塞线程,意味着线程能够一连处理其余职业。

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             Console.WriteLine($"{nameof(Main)} - start.");
 6             DoAsync();
 7             Console.WriteLine($"{nameof(Main)} - end.");
 8 
 9             Console.Read();
10         }
11 
12         private static async void DoAsync()
13         {
14             Console.WriteLine($"    {nameof(DoAsync)} - start.");
15 
16             await Task.Delay(500);
17 
18             Console.WriteLine($"    {nameof(DoAsync)} - end.");
19         }
20     }

图4-1

 

传送门

  入门:《初始接触 async/await
异步编制程序》

  上篇:《走进异步编制程序的社会风气 –
剖析异步方法(上)》

  下篇:《走进异步编制程序的世界 – 在 GUI
中实行异步操作》

 


 【原来的书文链接】

【参考】《Illustrated C# 2012》

一.职责等待(Wait)

调用职务的Wait方法能够隔绝职责直至职务完结,类似于线程的join。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Task task = Task.Run(() =>
 6             {
 7                 Console.WriteLine("线程执行Begin");
 8                 Thread.Sleep(2000);
 9                 Console.WriteLine("线程执行End");
10             });
11             Console.WriteLine("任务是否完成:{0}", task.IsCompleted);
12             task.Wait();//阻塞,直至任务完成
13             Console.WriteLine("任务是否完成:{0}", task.IsCompleted);
14             Console.ReadKey();
15         }
16     }

实行如下:

威尼斯人线上娱乐 23

注意

线程调用Wait方法时,系统一检查测线程要等待的Task是还是不是已经开始举行。尽管是线程则会卡住直到Task运行结束截至。但假使Task还不曾开端施行职分,系统恐怕(取决于TaskScheduler)使用调用Wait的线程来施行Task,那种情景下调用Wait的线程不会卡住,它会试行Task并立时回去。好处在于未有线程会被封堵,所以减少了能源占用。不佳的地点在于加入线程在调用Wait前已经获得了1个线程同步锁,而Task试图获取同3个锁,就会招致死锁的线程。

传送门

  入门:《起初接触 async/await 异步编制程序》

  上篇:《走进异步编制程序的世界 – 剖析异步方法(上)》

 


 【原来的小说链接】

【参考】《Illustrated C# 2012》

] 走进异步编制程序的世界, 走进异步编制程序的社会风气 –
剖析异步方法(下) 序 多谢我们的协理,那是前日揭橥《走进异步编制程序的社会风气 –
剖析异…

二.职分履市场价格势(TaskCreationOptions)

我们精通为了创立2个Task,必要调用构造函数并传递2个Action或Action<object>委托,倘使传递的是愿意三个Object的主意,还必须向Task的构造函数穿都要传给操作的实参。仍可以够选用向构造器传递1些TaskCreationOptions标识来决定Task的推市价势。

 TaskCreationOptions为枚举类型

枚举值 说明
None 默认。
PreferFairness 尽可能公平的方式安排任务,即先进先执行。
LongRunning 指定任务将是长时间运行的,会新建线程执行,不会使用池化线程。
AttachedToParent 指定将任务附加到任务层次结构中的某个父级
DenyChildAttach 任务试图和这个父任务连接将抛出一个InvalidOperationException
HideScheduler 强迫子任务使用默认调度而非父级任务调度

在暗许景况下,Task内部是运作在池化线程上,那种线程会分外适合推行短总结密集作业。要是要推行长阻塞操作,则要防止选取池化线程。

威尼斯人线上娱乐 ,在池化线程上运转三个长职务难点非常的小,不过尽管要同时运维多少个长义务(特别是会卡住的职分),则会对质量发生潜移默化。最好利用:TaskCreationOptions.LongRunning。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             int workerThreadsCount, completionPortThreadsCount;
 6             ThreadPool.GetAvailableThreads(out workerThreadsCount, out completionPortThreadsCount);
 7             Console.WriteLine("剩余工作线程数:{0},剩余IO线程数{1},主线程Id:{2}", workerThreadsCount, completionPortThreadsCount, Thread.CurrentThread.ManagedThreadId);
 8             Task task = Task.Factory.StartNew(() =>
 9             {
10                 Console.WriteLine("长任务执行,线程Id:{0}", Thread.CurrentThread.ManagedThreadId);
11                 Thread.Sleep(2000);
12             }, TaskCreationOptions.LongRunning);
13             Thread.Sleep(1000);
14             ThreadPool.GetAvailableThreads(out workerThreadsCount, out completionPortThreadsCount);
15             Console.WriteLine("剩余工作线程数:{0},剩余IO线程数{1},主线程Id:{2}", workerThreadsCount, completionPortThreadsCount, Thread.CurrentThread.ManagedThreadId);
16             Console.ReadKey();
17         }
18     }

试行结果如下:

威尼斯人线上娱乐 24

注意

1旦使运营I/O密集义务,则能够利用TaskCompletionSource和异步函数(asynchronous
functions),通过回调(一而再)完毕并发性,而是不经过线程达成。

比方使运营总结密集性职分,则可以运用1个劳动者/消费者队列,调整这么些职分的产出数量,制止出现线程和进程阻塞的难点。

 

持续(continuation)&三番五次选项(Task孔蒂nuationOptions)

延续(continuation)会告诉任务在成就后继续执行上边包车型客车操作。连续平常由贰个回调方法达成,它会在操作完毕未来实行贰次。给1个职务叠加一而再的章程有两种

1.GetAwaiter

任务的艺术GetAwaiter是Framework
四.5新扩大的,而C#
五.0的异步功效使用了那种艺术,由此它那一个首要。给1个职分叠加延续如下:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Task<int> task = Task.Run(() =>
 6              {
 7                  int total = 0;
 8                  for (int i = 0; i <= 100; i++)
 9                  {
10                      total += i;
11                  }
12                  Thread.Sleep(2000);
13                  return total;
14              });
15             var awaiter = task.GetAwaiter();
16             awaiter.OnCompleted(() =>
17             {
18                 int result = awaiter.GetResult();//在延续中获取Task的执行结果
19                 Console.WriteLine(result);
20             });
21             Console.ReadKey();
22         }
23     }

实行结果决定台会打字与印刷:5050。

调用GetAwaiter会回去2个等待者(awaiter)对象,它会让辅导(antecedent)义务在任务完毕(或出错)之后试行2个代理。已经实现的天职也足以增大学一年级个继续,那事延续会立刻施行。

注意

1.等待者(awaiter)能够是不管37二十一对象,但必须包罗特定的五个艺术和四个Boolean类型属性。

1   public struct TaskAwaiter<TResult> : ICriticalNotifyCompletion, INotifyCompletion
2     {
3         public bool IsCompleted { get; }
4         public TResult GetResult();
5         public void OnCompleted(Action continuation);
6     }

2.指导职分现身错误,那么当再而三代码调用awaiter.GetResult()时就会再度抛出万分。大家能够须求调用GetResult,而是直接待上访问起头职分的Result属性(task.Result)。

GetResult的收益是,当向导职分出现错误时,至极能够一向抛出而不封装在AggregateException中。

叁.万一出现一块上下文,那么会自行捕捉它,然后继续提交到那个上下文中。在无需一并上下文的场合下1般不应用这种艺术,使用ConfigureAwait代替它。它平日会使延续运行在向导职责所在的线程上,从而制止不须要的过载。

1    var awaiter = task.ConfigureAwait(false).GetAwaiter();

2.ContinueWith

另一种附加三番6遍的点子是调用任务的ContinueWith方法:

 1         static void Main(string[] args)
 2         {
 3             Task<int> task = Task.Run(() =>
 4             {
 5                 int total = 0;
 6                 for (int i = 0; i <= 100; i++)
 7                 {
 8                     total += i;
 9                 }
10                 Thread.Sleep(2000);
11                 return total;
12             });
13             task.ContinueWith(continuationAction =>
14             {
15                 int result = continuationAction.Result;
16                 Console.WriteLine(result);
17             });
18             Console.ReadKey();
19         }

ContinueWith本人会回来二个Task,它那1个适用于增多越来越多的承接。然后若是职责现身谬误,我们亟须一向处理AggregateException。

要是想让持续运转在统多少个线程上,必须钦点 TaskContinuationOptions.ExecuteSynchronously;否则它会弹回线程池。ContinueWith专门适用于并行编制程序场景。

3.继续选项(TaskContinuationOptions)

在使用ContinueWith时得以钦定职责的存在延续选项即TaskContinuationOptions,它的前三个枚举类型与事先说的TaskCreationOptions枚举提供的标识完全一样,补充后续几个枚举值:

枚举值 说明
LazyCancellation 除非先导任务完成,否则禁止延续任务完成(取消)。
NotOnRanToCompletion 指定不应在延续任务前面的任务已完成运行的情况下安排延续任务。
NotOnFaulted 指定不应在延续任务前面的任务引发了未处理异常的情况下安排延续任务。
NotOnCanceled 指定不应在延续任务前面的任务已取消的情况下安排延续任务。 
OnlyOnCanceled 指定只应在延续前面的任务已取消的情况下安排延续任务。
OnlyOnFaulted 指定只有在延续任务前面的任务引发了未处理异常的情况下才应安排延续任务。
OnlyOnRanToCompletion 指定只有在延续任务前面的任务引发了未处理异常的情况下才应安排延续任务。
ExecuteSynchronously 指定希望由先导任务的线程执行,先导任务完成后线程继续执行延续任务。

 

ExecuteSynchronously是指同步实践,八个职务都在同2个=线程1前壹后的试行。

ContinueWith结合TaskContinuationOptions使用的言传身教:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Task<int> task = Task.Run(() =>
 6             {
 7                 int total = 0;
 8                 for (int i = 0; i <= 100; i++)
 9                 {
10                     total += i;
11                 }
12                 if (total == 5050)
13                 {
14                     throw new Exception("错误");//这段代码可以注释或开启,用于测试
15                 }
16                 return total;
17             });
18             //指定先导任务无报错的延续任务
19             task.ContinueWith(continuationAction =>
20             {
21                 int result = continuationAction.Result;
22                 Console.WriteLine(result);
23             }, TaskContinuationOptions.NotOnFaulted);
24             //指定先导任务报错时的延续任务
25             task.ContinueWith(continuationAction =>
26             {
27                 foreach (Exception ex in continuationAction.Exception.InnerExceptions)//有关AggregateException异常处理后续讨论
28                 {
29                     Console.WriteLine(ex.Message);
30                 }
31             }, TaskContinuationOptions.OnlyOnFaulted);
32             Console.ReadKey();
33         }
34     }

执行结果会打字与印刷:报错,纵然注释掉抛出尤其的代码则会打字与印刷5050。

 

TaskCompletionSource

另一种创造职务的章程是选用TaskCompletionSource。它同意成立贰个义务,并得以职责分发给使用者,并且这个使用者能够利用该任务的任何成员。它的落到实处原理是通过三个能够手动操作的“附属”职分,用于提示操作实现或出错的光阴。

TaskCompletionSource的真的意义是成立三个不绑定线程的职务(手动调控义务工作流,能够使您把创立职分和成功任务分别)

这种办法分外适合I/O密集作业:能够使用全体职责的独到之处(它们能够生成再次回到值、极度和再而三),但不会在操作试行时期阻塞线程。

例如,如若二个任务急需等待2秒,然后回来十,大家的方法会再次回到在2个二秒后产生的职分,通过给职责叠加多个接二连三就足以在不打断任何线程的前提下打印这一个结果,如下:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var awaiter = Demo(2000).GetAwaiter();//得到任务通过延续输出返回值
 6             awaiter.OnCompleted(() =>
 7             {
 8                 Console.WriteLine(awaiter.GetResult());
 9             });
10             Console.WriteLine("主线程继续执行....");
11             Console.ReadKey();
12         }
13         static Task<int> Demo(int millis)
14         {
15             //创建一个任务完成源
16             TaskCompletionSource<int> taskCompletionSource = new TaskCompletionSource<int>();
17             var timer = new System.Timers.Timer(millis) { AutoReset = false };
18             timer.Elapsed += delegate
19             {
20                 timer.Dispose(); taskCompletionSource.SetResult(10);//写入返回值
21             };
22             timer.Start();
23             return taskCompletionSource.Task;//返回任务
24         }
25     }

实施结果:

威尼斯人线上娱乐 25

注意:假若频仍调用SetResult、SetException或SetCanceled,它们会抛出卓殊,而TryXXX会重回false。

 

职分撤废(CancellationTokenSource)

一对情景下,后台职责大概运行十分长日子,打消职务就丰盛有效了。.NET提供了1种标准的职务撤除机制可用来据他们说职务的异步格局

取消基于CancellationTokenSource类,该类可用以发送撤消请求。请求发送给引用CancellationToken类的任务,个中CancellationToken类与CancellationTokenSource类相关联。

采纳示例如下:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //构造函数 指定延迟2秒后自动取消任务
 6             CancellationTokenSource source = new CancellationTokenSource(2000);
 7             //注册一个任务取消后执行的委托
 8             source.Token.Register(() =>
 9             {
10                 Console.WriteLine("线程Id:{0} 任务被取消后的业务逻辑正在运行", Thread.CurrentThread.ManagedThreadId);
11             });
12             //启动任务,将取消标记源带入参数
13             Task.Run(() =>
14             {
15                 while (!source.IsCancellationRequested)//IsCancellationRequested为True时取消任务
16                 {
17                     Thread.Sleep(100);
18                     Console.WriteLine("线程Id:{0} 任务正在运行", Thread.CurrentThread.ManagedThreadId);
19                 }
20             }, source.Token);
21             //主线程挂起2秒后手动取消任务
22             {
23                 //Thread.Sleep(2000);
24                 //source.Cancel();//手动取消任务
25             }
26             //主线程不阻塞,2秒后自动取消任务
27             {
28                 source.CancelAfter(2000);
29             }
30             Console.ReadKey();
31         }
32     }

试行结果:

威尼斯人线上娱乐 26

根据Register主意绑定职分撤除后的寄托

1   public CancellationTokenRegistration Register(Action callback);
2   public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext);
3   public CancellationTokenRegistration Register(Action<object> callback, object state);
4   public CancellationTokenRegistration Register(Action<object> callback, object state, bool useSynchronizationContext);

手动裁撤职分Cancel方法

自动撤废职分

1.CancelAfter主意前面能够辅导参数钦点延迟多少后时间收回任务。

1   public void CancelAfter(TimeSpan delay);
2   public void CancelAfter(int millisecondsDelay);

2.CancellationTokenSource构造函数能够带领参数钦定延迟多少时间后撤销职务。

1   public CancellationTokenSource(TimeSpan delay);
2   public CancellationTokenSource(int millisecondsDelay);

职务绑定CancellationTokenSource目的,在Task源码中能够带领CancellationToken对象的运营任务措施都能够绑定CancellationTokenSource。

威尼斯人线上娱乐 27

 

异步等待 (Task.Delay)

 异步等待卓殊实用,因此它变成Task类的3个静态方法

 常用的行使方法有二种,如下:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //第1种
 6             {
 7                 Task.Delay(2000).ContinueWith((o) =>
 8                 {
 9                     Console.WriteLine("线程Id:{0},异步等待2秒后执行的逻辑", Thread.CurrentThread.ManagedThreadId);
10                 });
11             }
12             //第2种
13             {
14                 Task.Delay(3000).GetAwaiter().OnCompleted(() =>
15                 {
16                     Console.WriteLine("线程Id:{0},异步等待3秒后执行的逻辑", Thread.CurrentThread.ManagedThreadId);
17                 });
18             }
19             Console.WriteLine("主线程Id:{0},继续执行", Thread.CurrentThread.ManagedThreadId);
20             Console.ReadKey();
21         }
22     }

施行结果如下:

威尼斯人线上娱乐 28

Task.DelayThread.Sleep的异步版本。而它们的界别如下(引自 禅道 ):

一.Thread.Sleep 是手拉手延迟,Task.Delay异步延迟。

贰.Thread.Sleep 会阻塞线程,Task.Delay不会。

3.Thread.Sleep无法撤销,Task.Delay能够。

4. Task.Delay() 比 Thread.Sleep()
消耗越来越多的财富,但是Task.Delay()可用于为情势重返Task类型;可能根据CancellationToken撤除标识动态打消等待。

五. Task.Delay() 实质创造三个周转给定时期的职务, Thread.Sleep()
使当前线程休眠给按时期。

 

异常(AggregateException)

与线程分裂,职责能够每一日抛出格外。所以,假诺职务中的代码抛出2个未处理至极,那么这一个那二个会活动传送到调用Wait()或Task<TResult>的Result属性的代码上。
任务的尤其将会自动捕获并抛给调用者。为保障报告富有的十三分,CLXC60会将分外封装在AggregateException容器中,该容器公开的InnerExceptions天性中富含全部捕获的老大,从而更符合并行编制程序。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             try
 6             {
 7                 Task.Run(() =>
 8                 {
 9                     throw new Exception("错误");
10                 }).Wait();
11             }
12             catch (AggregateException axe)
13             {
14                 foreach (var item in axe.InnerExceptions)
15                 {
16                     Console.WriteLine(item.Message);
17                 }
18             }
19             Console.ReadKey();
20         }
21     }

上述示范调节台会展现:错误

注意

使用TaskIsFaultedIsCanceled脾性,就能够不重复抛出十分而检查评定出错的天职。
一.IsFaulted和IsCanceled都回来False,表示没错误爆发。
贰.IsCanceled为True,则职分抛出了OperationCanceledOperation(撤废线程正在实践的操作时在线程中抛出的要命)。
三.IsFaulted为True,则任务抛出另1种非常,而Exception属性包蕴了该错误。

1.Flatten

当子任务抛出卓殊时,通过调用Flatten方法,能够裁撤任意层次的嵌套以简化格外处理。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var parent = Task.Factory.StartNew(() =>
 6             {
 7                 int[] numbers = { 0 };
 8                 var childFactory = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.None);
 9                 childFactory.StartNew(() => 10 / numbers[0]);//除零
10                 childFactory.StartNew(() => numbers[1]);//超出索引范围
11                 childFactory.StartNew(() => throw null);//空引用
12             });
13             try
14             {
15                 parent.Wait();
16             }
17             catch (AggregateException axe)
18             {
19                 foreach (var item in axe.Flatten().InnerExceptions)
20                 {
21                     Console.WriteLine(item.Message);
22                 }
23             }
24             Console.ReadKey();
25         }
26     }

威尼斯人线上娱乐 29

2.Handle

 若是需求只捕获特定类型格外,天公地道抛别的门类的那些,Handle办法为此提供了一种连忙方式。

Handle接受1个predicate(极度断言),并在各类内部相当上运营此断言。

1 public void Handle(Func<Exception, bool> predicate);

假定断言重返True,它感觉该尤其是“已处理”,当有着特别过滤之后:

1.若是具备尤其是已处理的,相当不会抛出。

贰.比方存在卓殊未处理,就会协会1个新的AggregateException对象来含有这个尤其并抛出。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var parent = Task.Factory.StartNew(() =>
 6             {
 7                 int[] numbers = { 0 };
 8                 var childFactory = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.None);
 9                 childFactory.StartNew(() => 10 / numbers[0]);//除零
10                 childFactory.StartNew(() => numbers[1]);//超出索引范围
11                 childFactory.StartNew(() => throw null);//空引用
12             });
13             try
14             {
15                 try
16                 {
17                     parent.Wait();
18                 }
19                 catch (AggregateException axe)
20                 {
21                     axe.Flatten().Handle(ex =>
22                     {
23                         if (ex is DivideByZeroException)
24                         {
25                             Console.WriteLine("除零-错误处理完毕");
26                             return true;
27                         }
28                         if (ex is IndexOutOfRangeException)
29                         {
30                             Console.WriteLine("超出索引范围-错误处理完毕");
31                             return true;
32                         }
33                         return false;//所有其它 异常重新抛出
34                     });
35 
36                 }
37             }
38             catch (AggregateException axe)
39             {
40                 foreach (var item in axe.InnerExceptions)//捕获重新抛出的异常
41                 {
42                     Console.WriteLine(item.Message);
43                 }
44             }
45             Console.ReadKey();
46         }
47     }

推行结果:

威尼斯人线上娱乐 30

 

 结语

1.async和await那七个关键字下篇记录。

2.职务调度器(TaskScheduler)是Task之所以如此灵活的实质,大家常说Task是在ThreadPool上更升级化的包裹,其实非常大程度上归功于那一个目标,考虑下篇要不要说一下,但实则作者看的都头疼…

叁.Task类包括众多的重载,最棒F1二跳到Task内纯熟下结构。

 

参照文献 

CLR via C#(第4版) Jeffrey Richter

C#高档编制程序(第10版) C# 6 & .NET Core 1.0   Christian Nagel  

果壳中的C# C#5.0独尊指南  Joseph Albahari

C#并发编制程序 杰出实例  史蒂芬 Cleary

 


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图