在C#Async CTP中`等待'线程会发生什么?

dev*_*os1 23 .net c# async-await async-ctp

我一直在阅读关于新的异步await关键字,它听起来很棒,但有一个关键问题我到目前为止看过的任何一个介绍视频都找不到答案(我也读过白皮书)一会儿回来).

假设我await在主UI线程上的嵌套函数中有一个调用.此时线程会发生什么?控件是否返回消息循环,UI线程可以自由处理其他输入?

当等待的任务完成时,整个堆栈是否被推送到消息队列,这样控制将通过每个嵌套函数返回,或者其他完全发生在这里?

其次(虽然我引起了你的注意),我真的不明白为什么需要标记异步方法async.不能异步执行任何方法吗?如果我想异步执行一个方法但它没有async关键字怎么办?有没有办法简单地做到这一点?

干杯.:)

编辑: 不可否认,如果我能得到示例代码编译,我可能只是想出自己,但由于某种原因,我遇到了一个块.我真正想知道的是,延续的持续程度是多久...是否会冻结整个调用堆栈,在任务完成时恢复它,还是只返回到目前为止?是否需要将函数本身标记为异步以支持延续,或者(正如我最初所说)它是否继续整个调用堆栈?

如果它没有冻结整个调用堆栈,那么当异步等待命中非异步调用函数时会发生什么?它阻止了吗?这不会打败等待点吗?我希望你能看到我在这里缺少一些理解我希望有人可以填写,所以我可以继续学习这个.

Ste*_*ary 26

假设我在主UI线程上的嵌套函数中调用了await.此时线程会发生什么?控件是否返回消息循环,UI线程可以自由处理其他输入?

是.当你await等待(例如a Task<TResult>)时,线程在async方法中的当前位置被捕获.然后,当等待结束时(例如,当Task<TResult>完成时),它将对方法的剩余部分("继续")进行排队.

但是,可以进行优化:如果等待已经完成,则await不必等待,并且它只是立即继续执行该方法.这被称为"快速路径",在此描述.

当等待的任务完成时,整个堆栈是否被推送到消息队列,这样控制将通过每个嵌套函数返回,或者其他完全发生在这里?

线程的当前位置被推送到UI消息队列.细节是一个更复杂一点:延续目前预定TaskScheduler.FromCurrentSynchronizationContext除非SynchronizationContext.Currentnull,在这种情况下,他们被安排上TaskScheduler.Current.此外,可以通过调用来覆盖此行为,该调用ConfigureAwait(false)始终调度线程池上的延续.由于SynchronizationContext.CurrentSynchronizationContextWPF/WinForms/Silverlight 的UI ,因此该延续会被推送到UI消息队列.

其次(虽然我引起了你的注意),我真的不明白为什么异步方法需要用异步标记.不能异步执行任何方法吗?如果我想异步执行一个方法但它没有async关键字怎么办?有没有办法简单地做到这一点?

这些与"异步"一词略有不同.该async关键字使await关键字.换句话说,async方法可以await.老式的异步委托(即BeginInvoke/ EndInvoke)与完全不同async.异步委托在ThreadPool线程上执行,但async方法在UI线程上执行(假设它们是从UI上下文调用的,而您不调用ConfigureAwait(false)).

如果你想async在一个ThreadPool线程上运行(非)方法,你可以这样做:

await Task.Run(() => MyMethod(..));
Run Code Online (Sandbox Code Playgroud)

我真正想知道的是,延续的持续程度是多久...是否会冻结整个调用堆栈,在任务完成时恢复它,还是只返回到目前为止?是否需要将函数本身标记为异步以支持延续,或者(正如我最初所说)它是否继续整个调用堆栈?

捕获当前位置,并在继续运行时"恢复".await必须标记用于支持延续的任何函数async.

如果您async从非async方法调用方法,则必须Task直接处理该对象.通常不会这样做.顶级async方法可能会返回void,因此没有理由不使用async事件处理程序.

注意,这async纯粹是编译器转换.这意味着async方法在编译后与常规方法完全相同..NET运行时不会以任何特殊方式处理它们.

  • 没有; 我只是为了100%肯定而进行了测试.捕获的例外很好.请注意,异常包含在`Task`中,因此您需要"等待"它以查看异常.但随后它在调用堆栈中运行得很好. (2认同)