也就是asyn负责生成状态机和执行状态机,await将代码分为两部分,一部分是异步执行状态机部分,一部分是异步执行完之后,通过之前拿到的DispatcherSynchronizationContext,再去异步执行接下来的部分。我们可以通过dnspy调试DispatcherSynchronizationContext的 _dispatcher字段的Thread属性,知道Thread为UI主线程,而同步界面UI控件的时候,也就是通过Dispatcher的BeginInvoke函数去执行同步的
三.Task.ConfigureAwaitTask有个ConfigureAwait方法,是可以设置是否对Task的awaiter的延续任务执行原始上下文,也就是为true时,是以一开始那个UI主线程的DispatcherSynchronizationContext执行Post方法,而为false,则以await那个Task里面的DispatcherSynchronizationContext执行Post方法,我们来验证下:
我们将代码改为以下:
private async void Async_Click(object sender, RoutedEventArgs e) { Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}"); var result= await ExampleTask(2).ConfigureAwait(false); Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}"); Debug.WriteLine(result); Debug.WriteLine($"Async Completed"); }输出:
Thread Id is Thread:1,Is Thread Pool:False Thread Id is Thread:4,Is Thread Pool:True It's Async Completed in 2 seconds Async Completed结果和控制台输出的一模一样,且通过dnspy断点调试依旧进入到DispatcherSynchronizationContext的Post方法,因此我们也可以证明我们上面的猜想,而且默认ConfigureAwait的参数是为true的,我们还可以将异步结果赋值给UI界面的Text block:
private async void Async_Click(object sender, RoutedEventArgs e) { Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}"); var result= await ExampleTask(2).ConfigureAwait(false); Debug.WriteLine($"Thread Id is Thread:{Thread.CurrentThread.ManagedThreadId},Is Thread Pool:{Thread.CurrentThread.IsThreadPoolThread}"); this.txt.Text = result;//修改部分 Debug.WriteLine($"Async Completed"); }抛出异常:
调用线程无法访问此对象,因为另一个线程拥有该对象