一、await和async关键字
.Net平台不断推出了新的异步编程模型,在.net4.5中加入了关键字await和async,顾名思义,await是指方法执行可等待,即可挂起直到有结果(不是必须立即占用主进程),async标明此方法是异步方法
await 运算符在异步方法应用于任务,以挂起执行方法,直到所等待的任务完成。 任务表示正在进行的工作。
在其中使用 await 的异步方法必须通过 async 关键字进行修改。 使用 async 修饰符定义并且通常包含一个或多个 await 表达式的这类方法称为异步方法。
二、分析关键字结构及语法
先解析一下专业名词:
同步方法:一个程序调用某个方法,等到其执行完成之后才进行下一步操作。这也是默认的形式。
异步方法:一个程序调用某个方法,在处理完成之前就返回该方法。通过 async/await 我们就可以实现这种类型的方法。
async/await 结构可分成三部分:
(1)调用方法:该方法调用异步方法,然后在异步方法执行其任务的时候继续执行;
(2)异步方法:该方法异步执行工作,然后立刻返回到调用方法;
(3)await 表达式:用于异步方法内部,指出需要异步执行的任务。一个异步方法可以包含多个 await 表达式(不存在 await 表达式的话 IDE 会发出警告)。
异步方法:在执行完成前立即返回调用方法,在调用方法继续执行的过程中完成任务。
语法分析:
(1)关键字:方法头使用 async 修饰。
(2)要求:包含 N(N>0) 个 await 表达式(不存在 await 表达式的话 IDE 会发出警告),表示需要异步执行的任务。
(3)返回类型:只能返回 3 种类型(void、Task 和 Task<T>)。Task 和 Task<T> 标识返回的对象会在将来完成工作,表示调用方法和异步方法可以继续执行。
(4)参数:数量不限,但不能使用 out 和 ref 关键字。
(5)命名约定:方法后缀名应以 Async 结尾。
(6)其它:匿名方法和 Lambda 表达式也可以作为异步对象;async 是一个上下文关键字;关键字 async 必须在返回类型前。
三、异步调用http
private async void startButton_Click(object sender, RoutedEventArgs e) { // Disable the button until the operation is complete. startButton.IsEnabled = false; resultsTextBox.Clear(); // One-step async call. await SumPageSizesAsync(); //// Two-step async call. //Task sumTask = SumPageSizesAsync(); //await sumTask; resultsTextBox.Text += " Control returned to startButton_Click. "; // Reenable the button in case you want to run the operation again. startButton.IsEnabled = true; } private async Task SumPageSizesAsync() { // Declare an HttpClient object. HttpClient client = new HttpClient(); // Make a list of web addresses. List<string> urlList = SetUpURLList(); var total = 0; foreach (var url in urlList) { // GetByteArrayAsync returns a task. At completion, the task // produces a byte array. byte[] urlContents = await client.GetByteArrayAsync(url); // The following two lines can replace the previous assignment statement. //Task<byte[]> getContentsTask = client.GetByteArrayAsync(url); //byte[] urlContents = await getContentsTask; DisplayResults(url, urlContents); // Update the total. total += urlContents.Length; } // Display the total count for all of the websites. resultsTextBox.Text += string.Format(" Total bytes returned: {0} ", total); } private List<string> SetUpURLList() { List<string> urls = new List<string> { "http://msdn.microsoft.com/library/windows/apps/br211380.aspx", "http://msdn.com", "http://msdn.microsoft.com/en-us/library/hh290136.aspx", "http://msdn.microsoft.com/en-us/library/ee256749.aspx", "http://msdn.microsoft.com/en-us/library/hh290138.aspx", "http://msdn.microsoft.com/en-us/library/hh290140.aspx", "http://msdn.microsoft.com/en-us/library/dd470362.aspx", "http://msdn.microsoft.com/en-us/library/aa578028.aspx", "http://msdn.microsoft.com/en-us/library/ms404677.aspx", "http://msdn.microsoft.com/en-us/library/ff730837.aspx" }; return urls; } private void DisplayResults(string url, byte[] content) { // Display the length of each website. The string format // is designed to be used with a monospaced font, such as // Lucida Console or Global Monospace. var bytes = content.Length; // Strip off the "http://". var displayURL = url.Replace("http://", ""); resultsTextBox.Text += string.Format(" {0,-58} {1,8}", displayURL, bytes); }
四、其他示例
public class MyClass { public MyClass() { DisplayValue(); //这里不会阻塞 System.Diagnostics.Debug.WriteLine("MyClass() End."); } public Task<double> GetValueAsync(double num1, double num2) { return Task.Run(() => { for (int i = 0; i < 1000000; i++) { num1 = num1 / num2; } return num1; }); } public async void DisplayValue() { double result = await GetValueAsync(1234.5, 1.01);//此处会开新线程处理GetValueAsync任务,然后方法马上返回 //这之后的所有代码都会被封装成委托,在GetValueAsync任务完成时调用 System.Diagnostics.Debug.WriteLine("Value is : " + result); } }
要执行异步操作的方法用async标记,调用方法时用await标记,被异步调用的方法返回值用<task>修饰。
实际执行代码:
public void DisplayValue() { System.Runtime.CompilerServices.TaskAwaiter<double> awaiter = GetValueAsync(1234.5, 1.01).GetAwaiter(); awaiter.OnCompleted(() => { double result = awaiter.GetResult(); System.Diagnostics.Debug.WriteLine("Value is : " + result); }); }
以下为某大神写的静态类,可以将一般方法转化为异步调用:
public static class TaskAsyncHelper 02.{ 03. /// <summary> 04. /// 将一个方法function异步运行,在执行完毕时执行回调callback 05. /// </summary> 06. /// <param name="function">异步方法,该方法没有参数,返回类型必须是void</param> 07. /// <param name="callback">异步方法执行完毕时执行的回调方法,该方法没有参数,返回类型必须是void</param> 08. public static async void RunAsync(Action function, Action callback) 09. { 10. Func<System.Threading.Tasks.Task> taskFunc = () => 11. { 12. return System.Threading.Tasks.Task.Run(() => 13. { 14. function(); 15. }); 16. }; 17. await taskFunc(); 18. if (callback != null) 19. callback(); 20. } 21. 22. /// <summary> 23. /// 将一个方法function异步运行,在执行完毕时执行回调callback 24. /// </summary> 25. /// <typeparam name="TResult">异步方法的返回类型</typeparam> 26. /// <param name="function">异步方法,该方法没有参数,返回类型必须是TResult</param> 27. /// <param name="callback">异步方法执行完毕时执行的回调方法,该方法参数为TResult,返回类型必须是void</param> 28. public static async void RunAsync<TResult>(Func<TResult> function, Action<TResult> callback) 29. { 30. Func<System.Threading.Tasks.Task<TResult>> taskFunc = ()=> 31. { 32. return System.Threading.Tasks.Task.Run(()=> 33. { 34. return function(); 35. }); 36. }; 37. TResult rlt = await taskFunc(); 38. if(callback != null) 39. callback(rlt); 40. } 41.}
async用来修饰方法,表明这个方法是异步的,声明的方法的返回类型必须为:void,Task或Task<TResult>。
await必须用来修饰Task或Task<TResult>,而且只能出现在已经用async关键字修饰的异步方法中。通常情况下,async/await成对出现才有意义,
上面提到task.wait可以让主线程等待后台线程执行完毕,await和wait类似,同样是等待,等待Task<string>.Run()开始的后台线程执行完毕,不同的是await不会阻塞主线程
欢迎加入qq群交流:568055323