为什么需要异步,异步对可能起阻止作用的活动(例如,应用程序访问 Web 时)至关重要。 对 Web 资源的访问有时很慢或会延迟。 如果此类活动在同步过程中受阻,则整个应用程序必须等待。 在异步过程中,应用程序可继续执行不依赖 Web 资源的其他工作,直至潜在阻止任务完成。
在前面的章节已经知道了C#有三种方式进行异步调用:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication39 { class Program { static void Main(string[] args) { CountdownEvent handler = new CountdownEvent(2); //使用Thread调用 new Thread(() => { Test("Thread"); handler.Signal(); }).Start(); //使用线程池调用 ThreadPool.QueueUserWorkItem((state) => { Test("ThreadPool"); handler.Signal(); }); //使用Task调用 Task task = Task.Run(() => Test("Task")); Console.WriteLine("Main Thread"); //等待所有工作线程完成之后结束 handler.Wait(); //等待Task完成 Task.WaitAll(task); Console.WriteLine("Main End"); } static void Test(string caller) { Thread.Sleep(1000); Console.WriteLine("caller:{0} Hello World", caller); } } }其实不管是Task,ThreadPool,本质最终都是Thread。只不过微软帮我们在简化线程控制的复杂度。
线程池是CLR中事先定义好的一些线程。Task取的线程池,只不过在语法上,可以非常方便取返回值。
多线程会提高程序的效率,不会提高运行速度。
这就好比这一个任务让前台花1个小时。前台完成10分钟的时候
打电话给经理,让他安排一个人来干30分钟(new Thread()),他干剩下的20分钟。(创建线程,需要时间,内存资源)
或者从旁边空闲的同事中(ThreadPool 或 Task),拉一个人过来干30分钟。他干剩下的20分钟。(需要的时间少,资源本来就存在)
从上看出,异步会让一份任务时间变长。资源消耗更多。但是可以让前台(UI线程)空闲下来,听从领导(用户)指挥。
凡是使用await关键字的方法,都必须打上async标记。
async表示方法内有异步方法,调用async方法,会立刻另起线程执行。
await只是显示等待线程结束。await表示等待异步方法执行完,并取返回值。
using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication39 { class Program { static void Main(string[] args) { StartAsync(); //main不能使用async Console.WriteLine("这是Main方法,线程ID:{0}", CurrentThreadID); Console.Read(); } static async Task StartAsync() { Task<string> t_result = MethodAsync(); Thread.Sleep(500);//模拟执行大量耗时操作 Console.WriteLine("这是StartAsync方法,线程ID:{0}", CurrentThreadID); //完成标记 string result = await t_result; //等待取异步返回结果 Console.WriteLine("Main End {0},线程ID:{0}",result, CurrentThreadID); //主线程结束标记 } static async Task<string> MethodAsync() { return await Task.Run(() => { Console.WriteLine("这是MethodAsync方法0,线程ID:{0}", Thread.CurrentThread.ManagedThreadId.ToString()); Thread.Sleep(1000);//模拟执行大量耗时操作 Console.WriteLine("这是MethodAsync方法1,线程ID:{0}", CurrentThreadID); return "Hello World"; }); } public static string CurrentThreadID { get { return Thread.CurrentThread.ManagedThreadId.ToString(); } } } }