首页 > 解决方案 > 如何调用保证同步的异步方法

问题描述

我有一个或多或少看起来像这样的方法:

public async Task PossiblyAsync(bool amIlucky)
{
    if (amIlucky)
        await Task.Delay(9000);

    return;
}

在某些情况下,我确定不会在其中调用任何异步代码路径,但我仍然需要将所有事情都异步执行到最顶层。这本身不是问题,但我想知道当一个完美同步的代码假装是异步的时,它是否会引入一些不必要的开销,将所有结果包装在Task<T>其中并做谁知道的其他事情。

另外,我真的希望它不要在线程之间跳转。我不确定它是否会发生,特别是因为 asp net core 中没有同步上下文。但是话又说回来,我不太明白同步上下文是什么:)

调用这种方法的最正确方法是什么?

标签: c#asp.net-core.net-coreasync-await

解决方案


但我想知道当一个完美同步的代码假装是异步的时,它是否会引入一些不必要的开销,将所有结果包装在 Task 中并做其他人知道的事情。

通常不会太糟糕。国家机器制造商试图针对这种情况进行优化,并避免一切不必要的事情——Task.CompletedTask尽可能返回。但是,对于 return 的方法Task<T>,这并不容易获得——您可能想要切换到ValueTask<T>,因为这在“经常同步但需要返回值”的情况下更有效。在非常热的路径代码中(通常在 IO 库中),通常会在此处添加一个额外的层以完全避免状态机制,直到我们知道我们将要异步,但这是利基市场,可能超出了您的需要。


对于“避免状态机制”部分的示例(并再次强调大多数应用程序代码永远不需要这种级别的优化),请考虑:

ValueTask<Foo> SomeMethodAsync(...)
{
    ValueTask<Bar> theThing = DoTheThingAsync(...); // some other things that we need
    if (theThing.IsCompletedSuccessfully)
    {
        return new ValueTask<Foo>(ProcessResults(theThing.Result));
    }
    else
    {
        return Awaited(theThing);
    }

    static async ValueTask<Foo> Awaited(ValueTask<Bar> incomplete)
        => ProcessResults(await incomplete.ConfigureAwait(false));

    static Foo ProcessResults(Bar bar) {...whatever...}

推荐阅读