2、初识 async & await。
static void Main(string[] args)
{
Console.WriteLine("我是主线程,线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
TestAsync();
Console.ReadLine();
}
static async Task TestAsync()
{
Console.WriteLine("调用GetReturnResult()之前,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
var name = GetReturnResult();
Console.WriteLine("调用GetReturnResult()之后,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
Console.WriteLine("得到GetReturnResult()方法的结果:{0}。当前时间:{1}", await name, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
}
static async Task<string> GetReturnResult()
{
Console.WriteLine("执行Task.Run之前, 线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
return await Task.Run(() =>
{
Thread.Sleep(3000);
Console.WriteLine("GetReturnResult()方法里面线程ID: {0}", Thread.CurrentThread.ManagedThreadId);
return "我是返回值";
});
}
  结果:

  我们来看看程序的执行过程:

  由上面的结果可以得到如下结论:
  (1)在async标识的方法体里面,如果没有await关键字的出现,那么这种方法和调用普通的方法没什么区别。
  (2)在async标识的方法体里面,在await关键字出现之前,还是主线程顺序调用的,直到await关键字的出现才会出现线程阻塞。
  (3)await关键字可以理解为等待方法执行完毕,除了可以标记有async关键字的方法外,还能标记Task对象,表示等待该线程执行完毕。所以await关键字并不是针对于async的方法,而是针对async方法所返回给我们的Task。
  (4)是否async关键字只能标识返回Task对象的方法呢。我们来试试:

  异步方法的返回类型必须为void、Task或者Task<T>类型。也是说async要么是void,要么和Task关联。
  3、除了await关键字,Task对象还有另外一种方式等待执行结果。
  static async Task TestAsync()
  {
  Console.WriteLine("调用GetReturnResult()之前,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
  var name = GetReturnResult();
  Console.WriteLine("调用GetReturnResult()之后,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
  Console.WriteLine("得到GetReturnResult()方法的结果:{0}。当前时间:{1}", name.GetAwaiter().GetResult(), DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
  }
  这样可以得到相同的结果。
  name.GetAwaiter()这个方法得到的是一个TaskAwaiter对象,这个对象表示等待完成的异步任务的对象,并提供结果的参数。所以除了能完成await关键字的等待之外,它还能做一些其他的操作。我们将TaskAwaiter转到定义
  public struct TaskAwaiter<TResult> : ICriticalNotifyCompletion, INotifyCompletion
  {
  public bool IsCompleted { get; }
  public TResult GetResult();
  public void OnCompleted(Action continuation);
  public void UnsafeOnCompleted(Action continuation);
  }
  IsCompleted:获取一个值,该值指示异步任务是否已完成。
  GetResult():得到执行的结果。这个方法和await关键字效果相同。
  OnCompleted():传入一个委托,在任务执行完成之后执行。
  UnsafeOnCompleted():计划与此 awaiter 相关异步任务的延续操作。
  由此可以看出,await关键字实际上是调用了TaskAwaiter对象的GetResult()方法。