第5章:使用C#5.0
1、异步函数async
1)、异步函数需要使用async关键词标注方法,异步函数必须返回Task或Task<int>,可以使用async void方法(唯一合理在程序UI控制器事件处理器中),其余更推荐async Task。
2)、async方法内部,可以使用await操作符,在async外不能使用await,另外异步函数至少要一个await关键字。
3)、await调用后方法立即返回,即GetStringAsync()不会Thread.Sleep(2),而是在取Result的时候等待。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
async static Task<string> GetStringAsync() { await Task.Delay(TimeSpan.FromSeconds(2)); return "Hello World!"; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
static void Main(string[] args) { Console.WriteLine(DateTime.Now); var str = GetStringAsync(); Console.WriteLine(DateTime.Now); //Thread.Sleep(TimeSpan.FromSeconds(5)); Console.WriteLine(str.Result); Console.WriteLine(DateTime.Now); Console.Read(); }
--如果是两个await,两个await不是两个异步任务,而是先完成前面的await才去做下一个await,从而避免Task这种不知道执行顺序的尴尬。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
async static Task<string> GetStringAsync() { await Task.Delay(TimeSpan.FromSeconds(2)); await Task.Delay(TimeSpan.FromSeconds(2)); return "Hello World!"; } static void Main(string[] args) { Console.WriteLine(DateTime.Now); var str = GetStringAsync(); Console.WriteLine(DateTime.Now); //Thread.Sleep(TimeSpan.FromSeconds(5)); Console.WriteLine(str.Result); // 等待4秒而不是2秒 Console.WriteLine(DateTime.Now); Console.Read(); }
--不能再catch、finally、lock或unsafe中使用await,不允许异步函数使用ref和out
2、使用await操作符获取异步任务结果
-- 有异常的时候,TaskContinuationOptions.OnlyOnFaulted;没有异常的时候,TaskContinuationOptions.NotOnFaulted。
--Task.wait(),Task.Result()不推荐在GUI和asp.net中使用
-- TPL模式
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
static Task AsynchronyWithTPL() { Task<string> t = GetInfoAsync("Task 1"); Task t2 = t.ContinueWith(task => Console.WriteLine(t.Result), TaskContinuationOptions.NotOnFaulted); Task t3 = t.ContinueWith(task => Console.WriteLine(t.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted); return Task.WhenAny(t2, t3); } async static Task<string> GetInfoAsync(string name) { await Task.Delay(TimeSpan.FromSeconds(2)); //throw new Exception("Boom!"); return string.Format($"{name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." + $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}"); } static void Main(string[] args) { Task t = AsynchronyWithTPL(); t.Wait(); Console.Read(); }
--用async、await方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
async static Task AsynchronyWithAwait() { try { string result = await GetInfoAsync("Task 2"); Console.WriteLine(result); } catch (Exception ex) { Console.WriteLine(ex); } } async static Task<string> GetInfoAsync(string name) { await Task.Delay(TimeSpan.FromSeconds(2)); //throw new Exception("Boom!"); return string.Format($"{name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." + $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}"); } static void Main(string[] args) { Task t = AsynchronyWithAwait(); t.Wait(); Console.Read(); }
3、在lambda表达式中使用await操作符
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
async static Task AsynchronyProcessing() { Func<string, Task<string>> asyncLambda = async name => { await Task.Delay(TimeSpan.FromSeconds(2)); return $"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." + $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}"; }; string result = await asyncLambda("async lambda"); Console.WriteLine(DateTime.Now); Console.WriteLine(result); } static void Main(string[] args) { Task t = AsynchronyProcessing(); Console.WriteLine(DateTime.Now); t.Wait(); Console.Read(); }
4、对连续的异步任务使用await操作符
-- 通过Task.ContinueWith来分步执行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
static Task AsynchronyWithTPL() { var containerTask = new Task(() => { Task<string> t = GetInfoAsync("TPL 1"); t.ContinueWith(task => { Console.WriteLine(t.Result); Task<string> t2 = GetInfoAsync("TPL 2"); t2.ContinueWith(innerTask => Console.WriteLine(innerTask.Result), TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.AttachedToParent); t2.ContinueWith(innerTask => Console.WriteLine(innerTask.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent); }, TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.AttachedToParent); t.ContinueWith(task => Console.WriteLine(t.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent); }); containerTask.Start(); return containerTask; } async static Task<string> GetInfoAsync(string name) { Console.WriteLine($"Task {name} started"); await Task.Delay(TimeSpan.FromSeconds(2)); if (name == "TPL 2") { throw new Exception("Boom!"); } return $"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." + $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}"; } static void Main(string[] args) { Task t = AsynchronyWithTPL(); t.Wait(); Console.Read(); }
-- await更简单,异步函数并不一定是并行执行的,可能是顺序执行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
async static Task AsynchronyWithAwait() { try { string result = await GetInfoAsync("Async 1"); Console.WriteLine(result); result = await GetInfoAsync("Async 2"); Console.WriteLine(result); } catch (Exception e) { Console.WriteLine(e); } } async static Task<string> GetInfoAsync(string name) { Console.WriteLine($"Task {name} started"); await Task.Delay(TimeSpan.FromSeconds(2)); if (name == "TPL 2" || name == "Async 2") { throw new Exception("Boom!"); } return $"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." + $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}"; } static void Main(string[] args) { Task t = AsynchronyWithAwait(); t.Wait(); Console.Read(); }
5、对并行执行的异步任务使用await操作符
--Task 1和Task 2在线程池不同线程中执行,是并行任务。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
async static Task AsynchronyProcessing() { Task<string> t1 = GetInfoAsync("Task 1", 3); Task<string> t2 = GetInfoAsync("Task 2", 5); string[] results = await Task.WhenAll(t1, t2); foreach (string result in results) { Console.WriteLine(result); } } async static Task<string> GetInfoAsync(string name, int seconds) { Console.WriteLine($"1、{name}---{DateTime.Now}"); await Task.Delay(TimeSpan.FromSeconds(seconds)); Console.WriteLine($"2、{name}---{DateTime.Now}"); await Task.Run(() => { Thread.Sleep(TimeSpan.FromSeconds(seconds)); }); Console.WriteLine($"3、{name}---{DateTime.Now}"); return $"{name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." + $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}"; } static void Main(string[] args) { Task t = AsynchronyProcessing(); t.Wait(); Console.Read(); }