异步方法在第一次"等待"之前是否有昂贵的代码?

Law*_*eld 9 .net c# task-parallel-library async-ctp

在第一个await被调用之前,在异步方法的开头有昂贵的代码是不是很糟糕?这个代码应该用一个包裹TaskEx.Run吗?

public async Task Foo()
{
    // Do some initial expensive stuff.
    // ...

    // First call to an async method with await.
    await DoSomethingAsync;
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 10

正如里德所说,这实际上取决于背景.代码必须在某个时刻运行- 但是根据上下文,它可能最终在线程池线程上运行而不是一些关键线程.

而不是使用Task.Run,我会使用TaskEx.Yield:

public async Task Foo()
{
    await TaskEx.Yield();
    // Do expensive stuff
}
Run Code Online (Sandbox Code Playgroud)

据我所知,这基本上是一种立即返回调用者的方法,但允许其他异步方法直接安排.如果您使用的是Windows窗体UI线程,那么这样做是没有意义的,因为您将立即回到UI线程(并在那里运行昂贵的代码) - 但如果您处于上下文中则会有意义不应阻止当前线程,但在另一个线程上运行continuation.


Ree*_*sey 5

这不一定是坏事,但可能会产生意想不到的后果.如果调用者希望代码完全异步,那么昂贵的代码将同步运行.这将导致它的行为部分类似于同步方法,但也是异步的,这是两个世界中最糟糕的一种(异步的额外复杂性,没有复制性......)

如果可能的话,我建议尝试尽可能少的"昂贵"代码导致第一个等待.使用Task.Run(或TaskEx.Run在CTP中)包装昂贵的代码,或将昂贵的代码移动到它自己的异步方法(在你可以的await情况下)将在这种情况下是有益的.