异步方法在第一个'await'之前有昂贵的代码

本文关键字:代码 await 第一个 异步方法 | 更新日期: 2023-09-27 18:17:26

在调用第一个await之前,在异步方法开始时使用昂贵的代码是不好的吗?这段代码应该用TaskEx.Run来包装吗?

public async Task Foo()
{
    // Do some initial expensive stuff.
    // ...
    // First call to an async method with await.
    await DoSomethingAsync;
}

异步方法在第一个'await'之前有昂贵的代码

正如Reed所说,这实际上取决于上下文。代码必须在某个点上运行——但根据上下文,它可能最终在线程池线程上运行,而不是在某个关键线程上运行。

不使用Task.Run,我将使用TaskEx.Yield:

public async Task Foo()
{
    await TaskEx.Yield();
    // Do expensive stuff
}

据我所知,这基本上是一种立即返回调用者的方式,但允许异步方法的其余部分直接被调度。如果你在Windows窗体UI线程中,这样做没有意义,因为你会立即回到UI线程(并在那里运行昂贵的代码)-但如果你在当前线程不应该被阻塞的上下文中,但继续在另一个线程上运行,这将是有意义的。

这并不一定是坏事,但可能会产生意想不到的后果。如果调用者期望代码完全异步运行,那么开销大的代码将同步运行。这将导致它的行为部分像同步方法,但也是异步的,这是两种世界中最糟糕的(异步带来的额外复杂性而没有响应性…)

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