一、在调用方法中同步地等待任务
static class MyDownloadString { public static void DoRun() { Task<int> t = CountCharactersAsync("https://www.baidu.com"); //t.Wait(); Console.WriteLine("Main threading"); } private static async Task<int> CountCharactersAsync(string site) { Thread.Sleep(1000); string result = await new WebClient().DownloadStringTaskAsync(new Uri(site)); Console.WriteLine("The task has finished,returning value:{0}", result.Length); return result.Length; } } class Program { static void Main(string[] args) { MyDownloadString.DoRun(); Console.ReadLine(); } }
调用方法虽然可以调用任意多个异步方法并接收他们返回的Task对象,然后代码继续执行其他任务,但在某个点上可能会需要等待某个特殊Task对象完成,然后再继续,参考上面的代码。Task实例提供了一个Wait()方法,可以在Task对象上调用该方法。
在不使用t.Wait()方法时,输出如下:
Main threading
The task has finished,returning value:14462
使用t.Wait()时,输出如下:
The task has finished,returning value:14462
Main threading
可见,Wait使主线程同步地等待任务结束反馈后才输出Main Threading。
Wait方法用于单一Task对象。如果要等待一组Task对象,对于一组Task,WaitAll()可以等待所有任务都结束,WaitAny()可以等待某一个任务结束。
Task<T> t1=AsyncMethod(...); Task<T> t2=AsyncMethod(...); ... Task<T>[] tasks=new Tasks<T>[]{t1,t2}; Task.WaitAll(tasks); //Task.WaitAny(tasks);
二、在异步方法中异步地等待任务
有时在异步方法中,会希望用await表达式来等待Task,这时异步方法会返回到调用方法,但该异步方法会等待一个或所有任务完成。可以通过Task.WhenAll()和Task.WhenAny()方法来完成。这两个方法被称为组合子。
Task.WhenAll会异步地等待所有与之相关的Task完成,而不会占用主线程事件。
class MyDownloadString { public void DoRun() { Task<int> t = CountCharactersAsync("https://www.baidu.com", "http://www.sougou.com"); Console.WriteLine("DoRun:Task {0} finished", t.IsCompleted ? "" : "Not"); Console.WriteLine("Main thread"); Console.WriteLine("DoRun:Result={0}", t.Result); } private async Task<int> CountCharactersAsync(string site1,string site2) { WebClient wc1 = new WebClient(); WebClient wc2 = new WebClient(); Task<string> t1 = wc1.DownloadStringTaskAsync(new Uri(site1)); Task<string> t2 = wc2.DownloadStringTaskAsync(new Uri(site2)); List<Task<string>> tasks=new List<Task<string>>(); tasks.Add(t1); tasks.Add(t2); await Task.WhenAll(tasks); Console.WriteLine("t1 {0} finished",t1.IsCompleted?"":"Not"); Console.WriteLine("t2 {0} finished",t2.IsCompleted?"":"Not"); return t1.IsCompleted ? t1.Result.Length : t2.Result.Length; } } class Program { static void Main(string[] args) { MyDownloadString ds = new MyDownloadString(); ds.DoRun(); Console.ReadLine(); } }
输出:
DoRun:Task Not finished
Main thread
t1 finished
t2 finished
DoRun:Result=14462
如果换为WhenAny,输出则变为:
DoRun:Task Not finished
Main thread
t1 Not finished
t2 finished
DoRun:Result=16597
Task.WhenAny组合子会异步地等待与之相关的某个Task完成。