async 关键字应该是说替这个方法声明了IAsyncStateMachine,但与线程无关,所以void函数也能用async修饰。await也与线程无关,它只是设置TaskAwaiter.OnComplete。是否创建线程,需要由await后面的东西自己来决定。
后面的东西不一定是一个async的函数,你可以在那里创建post一个action/funtion到thread pool,然后在这个action/function内部(需要返回结果),设置TaskCompletionSource.SetResult,将你以前返回给别人的Task转移到Completed状态,这里又值得注意,Task本身都和线程没什么关系!Task更多是用来让别人追踪你的任务的执行状态的,你可以在线程里面操作Task,也可以在同步函数里面操作,对别人而言,都是await你的Task。
一个任务如果想支持被取消,那么要在参数中传入一个CancellationToken。因为Task本身在async函数里都看不见。Task本身没有取消的方法。
一个任务想要支持超时,那么就用Task.WhenAny,将这个任务和另一个单纯的等待的Task绑定在一起。另外一个任务结束,结果也被处理逻辑丢弃了。如果想要做得更干净,可以传递一个CancelllationToken给真正的任务,可以在超时的任务结束后,调用CancellationTokenSource.Cancel()。
Task.GetResult,与TaskAwaiter不同(通过回调,但如何切换回当前线程?还是说一直没有离开当前线程?应该是切换回来才对)是通过SpinWait或ManualResetEventSlim来实现的一个等待操作,这个操作,这就像最原始的代码通过Thread.Sleep等待是一样的,会阻塞当前线程,但任务的真正运行是在另一个线程里面的。
返回Task的方法,应该在方法中启动task的运行,或者至少有地方设置Task为Completed, Canceled,Faulted,否则的话, await task的不是傻等着了? new一个Task但不做任何事情,应该是不行的。
async/await的实现仍然不够直观。特别是CancellationTokenSource\CompletionSource。人的第一反应,应该是直接操纵异步函数返回的Task,通过这个Task实现完成或者取消,但现在居然是还要另外用到和CancellationTokenSource\CompletionSource。