async & await 的前世今生
来源:互联网 发布:维戈 莫特森 知乎 编辑:程序博客网 时间:2024/05/21 06:43
原文:async & await 的前世今生
1. 铺垫基础知识:
using System;using System.Threading;using System.Threading.Tasks;namespace ConsoleApp4{ class Program { static void Main() { Console.WriteLine("1. 创建"); Create(); Console.WriteLine("2. 线程池"); ThreadPoolTest(); Console.WriteLine("3. 传入参数"); ParaTest(); Console.WriteLine("4. 返回值"); ReturnTest(); Console.WriteLine("5. Semaphore 信号量(锁很好理解,忽视)"); SemaphoreSlimTest(); Console.WriteLine("6. 异常"); //ThreadExceptionTest(); //TaskExceptionTest(); Console.Read(); } public static void TaskExceptionTest() { try { var task = Task.Run(() => { GoException(); }); task.Wait(); // 在调用了这句话之后,主线程才能捕获task里面的异常 // 对于有返回值的Task, 我们接收了它的返回值就不需要再调用Wait方法了 // GetName 里面的异常我们也可以捕获到 var task2 = Task.Run(() => { GetNameExeception(); }); task2.Wait(); //var name = task2.Result; } catch (AggregateException ex) { foreach(Exception ex2 in ex.InnerExceptions) Console.WriteLine("Exception!{0}", ex2.Message); } } private static void GetNameExeception() { throw new Exception("Task Exeception."); } public static void ThreadExceptionTest() { try { new Thread(GoException).Start(); } catch (Exception ex) { // 其它线程里面的异常,我们这里面是捕获不到的。 Console.WriteLine("Thread Exception!"); } } static void GoException() { throw new Exception("Go Exception"); } static SemaphoreSlim _sem = new SemaphoreSlim(3); // 我们限制能同时访问的线程数量是3 static void SemaphoreSlimTest() { for (int i = 1; i <= 5; i++) { new Thread(Enter).Start(i); } } static void Enter(object id) { Console.WriteLine(id + " 开始排队..."); _sem.Wait(); Console.WriteLine("{0} 开始执行!, 将允许进入 SemaphoreSlim 线程数: {1}", id, _sem.CurrentCount); Thread.Sleep(1000 * (int)id); Console.WriteLine(id + " 执行完毕,离开!"); _sem.Release(); } static void ReturnTest() { // GetDayOfThisWeek 运行在另外一个线程中 var dayName = Task.Run<string>(() => { return GetDayOfThisWeek(); }); Console.WriteLine("今天是:{0}", dayName.Result); } private static string GetDayOfThisWeek() { return DateTime.Now.DayOfWeek.ToString(); } private static void ParaTest() { new Thread(Go2).Start("arg1"); // 没有匿名委托之前,我们只能这样传入一个object的参数 new Thread(delegate () { // 有了匿名委托之后... GoGoGo("arg1", "arg2", "arg3"); }).Start(); new Thread(() => { // 当然,还有 Lambada GoGoGo("arg1", "arg2", "arg3"); }).Start(); Task.Run(() => { // Task能这么灵活,也是因为有了Lambda呀。 GoGoGo("arg1", "arg2", "arg3"); }); } public static void GoGoGo(string arg1, string arg2, string arg3) { Console.WriteLine("1.{0}; 2.{1}; 3.{2}",arg1,arg2,arg3); } private static void ThreadPoolTest() { Console.WriteLine("我是主线程:Thread Id {0}", Thread.CurrentThread.ManagedThreadId); ThreadPool.QueueUserWorkItem(Go2); } public static void Go2(object data) { Console.WriteLine("我是另一个线程:Thread Id {0}, 参数值:{1}" , Thread.CurrentThread.ManagedThreadId , data ); } private static void Create() { new Thread(Go).Start(); // .NET 1.0开始就有的 Task.Factory.StartNew(Go); // .NET 4.0 引入了 TPL Task.Run(new Action(Go)); // .NET 4.5 新增了一个Run的方法 } public static void Go() { Console.WriteLine("我是另一个线程"); } }}
2. 一个小例子认识async & await
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace ConsoleApp5{ class Program { static void Main(string[] args) { Test(); // 这个方法其实是多余的, 本来可以直接写下面的方法 // await GetName() // 但是由于控制台的入口方法不支持async,所有我们在入口方法里面不能 用 await Console.WriteLine("Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); Console.Read(); } static async Task Test() { // 方法打上async关键字,就可以用await调用同样打上async的方法 // await 之后不会开启新的线程(await 从来不会开启新的线程) await GetName(); } static async Task GetName() { // Delay 方法来自于.net 4.5 await Task.Delay(1000); // 返回值前面加 async 之后,方法里面就可以用await了 Console.WriteLine("Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("In antoher thread....."); } }}
3. 看清什么时候才创建线程:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace ConsoleApp6{ class Program { static void Main(string[] args) { Console.WriteLine("Main Thread Id: {0}\r\n", Thread.CurrentThread.ManagedThreadId); Test(); Console.ReadLine(); } static async Task Test() { Console.WriteLine("Before calling GetName, Thread Id: {0}\r\n", Thread.CurrentThread.ManagedThreadId); var name = GetName(); //我们这里没有用 await,所以下面的代码可以继续执行 // 但是如果上面是 await GetName(),下面的代码就不会立即执行,输出结果就不一样了。 Console.WriteLine("End calling GetName.\r\n"); Console.WriteLine("Get result from GetName: {0}", await name); Console.WriteLine("end."); } static async Task<string> GetName() { // 这里还是主线程 Console.WriteLine("Before calling Task.Run, current thread Id is: {0}", Thread.CurrentThread.ManagedThreadId); return await Task.Run(() => { Thread.Sleep(1000); Console.WriteLine("'GetName' Thread Id: {0}", Thread.CurrentThread.ManagedThreadId); return "Jesse"; }); } }}
不用 await 关键字, 如何确认Task已执行完?
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace ConsoleApp6{ class Program { static void Main() { var task = Task.Run(() => { return GetName(); }); task.GetAwaiter().OnCompleted(() => { // 2 秒之后才会执行这里 var name = task.Result; Console.WriteLine("My name is: " + name); }); Console.WriteLine("主线程执行完毕"); Console.ReadLine(); } static string GetName() { Console.WriteLine("另外一个线程在获取名称"); Thread.Sleep(2000); return "Jesse"; } }}
Task 如何让线程挂起?
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace ConsoleApp6{ class Program { static void Main() { var task = Task.Run(() => { return GetName(); }); var name = task.GetAwaiter().GetResult(); Console.WriteLine("My name is:{0}", name); Console.WriteLine("主线程执行完毕"); Console.ReadLine(); } static string GetName() { Console.WriteLine("另外一个线程在获取名称"); Thread.Sleep(2000); return "Jesse"; } }}
Task.GetAwait()方法会给我们返回一个awaitable的对象,通过调用这个对象的GetResult方法就会挂起主线程,当然也不是所有的情况都会挂起。还记得我们Task的特性么? 在一开始的时候就启动了另一个线程去执行这个Task,当我们调用它的结果的时候如果这个Task已经执行完毕,主线程是不用等待可以直接拿其结果的,如果没有执行完毕那主线程就得挂起等待了。
await 实质是在调用awaitable对象的GetResult方法
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace ConsoleApp6{ class Program { static void Main() { Test(); Console.ReadLine(); } static async Task Test() { Task<string> task = Task.Run(() => { Console.WriteLine("另一个线程在运行!"); // 这句话只会被执行一次 Thread.Sleep(2000); return "Hello World"; }); // 这里主线程会挂起等待,直到task执行完毕我们拿到返回结果 var result = task.GetAwaiter().GetResult(); Console.WriteLine(result); // 这里不会挂起等待,因为task已经执行完了,我们可以直接拿到结果 var result2 = await task; Console.WriteLine(result2); } }}
阅读全文
0 0
- async & await 的前世今生
- async & await 的前世今生
- async & await 的前世今生
- async & await 的前世今生
- async & await 的前世今生(Updated)
- async & await 的前世今生(Updated)
- async & await 的前世今生(Updated)2014-02-24 08:24 by Jesse Liu,
- 5分种让你了解javascript异步编程的前世今生,从onclick到await/async
- 5分种让你了解javascript异步编程的前世今生,从onclick到await/async
- ES7的Async/Await
- ES7的Async/Await
- ES7的Async/Await
- 前世今生的缘
- 互联网的前世今生
- 救世主的前世今生
- 3G的前世今生
- Gentoo的前世今生
- Mozilla的前世今生
- Unicode字符集下CString/tchar*与char *转换 (解决中文乱码等)
- 51nod 动态数组基础教程 5
- 在ubuntu系统中配置Qt和opencv
- MyBatis学习系列之一
- java集合(一)总图
- async & await 的前世今生
- win10 internet临时文件删不掉的完美解决方法!
- [nyoj 10 ] skiing [ 记忆化搜索]
- Lucene 6.1 Demo
- 剑指offer:整数中1出现的次数(从1到n整数中1出现的次数)
- CSS详解(一)
- ImageLoder加载图片
- Zigzag Convert
- 【Python】Python简单的图片识别