【问题标题】:Can async methods have expensive code before the first 'await'?在第一个“等待”之前,异步方法可以有昂贵的代码吗?
【发布时间】:2011-12-09 17:09:08
【问题描述】:
在调用第一个 await 之前,在异步方法的开头使用昂贵的代码是不是很糟糕?这段代码是否应该用TaskEx.Run 包裹起来?
public async Task Foo()
{
// Do some initial expensive stuff.
// ...
// First call to an async method with await.
await DoSomethingAsync;
}
【问题讨论】:
标签:
c#
.net
task-parallel-library
async-ctp
【解决方案1】:
正如 Reed 所说,这实际上取决于上下文。代码必须在 some 点运行 - 但根据上下文,它可能最终在线程池线程而不是某个关键线程上运行。
我不会使用Task.Run,而是使用TaskEx.Yield:
public async Task Foo()
{
await TaskEx.Yield();
// Do expensive stuff
}
据我所知,这基本上是一种立即返回调用者的方式,但允许立即安排其余的异步方法。如果您处于 Windows 窗体 UI 线程之类的东西中,那么这样做是没有意义的,因为您将立即返回 UI 线程(并在那里运行昂贵的代码) - 但如果您处于上下文中,这将是有意义的当前线程不应该被阻塞,但继续在另一个线程上运行。
【解决方案2】:
不一定是坏事,但可能会产生意想不到的后果。如果调用者期望代码完全异步运行,那么昂贵的代码将同步运行。这将导致它部分表现得像一个同步方法,但也是异步的,这是两全其美的(没有响应性的异步带来的额外复杂性......)
如果可能的话,我建议尽量减少导致第一次等待的“昂贵”代码。在这种情况下,使用 Task.Run(或 CTP 中的 TaskEx.Run)包装昂贵的代码,或将昂贵的代码移动到其自己的异步方法中(在此基础上您可以 await)将是有益的。