简体   繁体   English

没有等待的异步方法与Task.FromResult

[英]Async method with no await vs Task.FromResult

Consider the following interface: 请考虑以下界面:

public interface IProvider
{
    Task<bool> Contains(string key);
}

This is implementation satisfies Visual Studio 这是实现满足Visual Studio

public Task<bool> Contains(string key)
{
    return Task.FromResult(false);
}

This implementation is convenient to write and would seem to achieve the same thing: 这种实现方便编写 ,似乎可以实现同样的目的:

public async Task<bool> Contains(string key)
{
    return false;
}

However, Visual Studio throws a hissy-fit and insists: 然而,Visual Studio引发了一种混乱并坚持:

This async method lacks 'await' operators and will run synchronously. 这种异步方法缺少“等待”运算符并将同步运行。 Consider using the 'await' operator to await non-blocking API calls, or 'await TaskEx.Run(...)' to do CPU-bound work on a background thread. 考虑使用'await'运算符等待非阻塞API调用,或'await TaskEx.Run(...)'在后台线程上执行CPU绑定工作。

I'd love to just ignore that warning and avoid using Task.FromResult(...) . 我很乐意忽略这个警告并避免使用Task.FromResult(...)

Are there any negative consequences to using the latter option? 使用后一种选择会产生任何负面影响吗?

The reason for that "hissy fit" is that the compiler needs to do a lot of work to present a task that works in all the expected right ways here, which you can see by compiling and decompiling it “hissy fit”的原因是编译器需要做很多工作来提供一个在这里以所有预期正确方式工作的任务,你可以通过编译和反编译来看到

Task.FromResult is cleaner, but may still have overhead - IIRC there are some scenarios where a Task.FromResult might work efficiently here (returning the same object each time), but I wouldn't rely on it. Task.FromResult更干净,但可能仍然有开销 - IIRC有一些场景,其中Task.FromResult可能在这里高效工作(每次返回相同的对象),但我不会依赖它。

There are 2 pragmatic reliable approaches: 有两种实用可靠的方法:

  • return a reused static Task<bool> result each time 每次返回一个重用的静态Task<bool>结果
  • use ValueTask<bool> - which seems ideal here if you are returning synchronously a lot of the time 使用ValueTask<bool> - 如果你在很多时候同步返回,这似乎是理想的

ie

private readonly static Task<bool> s_False = Task.FromResult(false);
public Task<bool> Contains(string key, string scope)
{
    return s_False ;
}

or 要么

public ValueTask<bool> Contains(string key, string scope)
{
    return new ValueTask<bool>(false);
}

Note: the second of these may not be possible in this case, since you didn't define the interface. 注意:在这种情况下,第二个可能是不可能的,因为您没有定义接口。 But: if you ever are designing an interface that needs to allow async usage but which may actually be sync: consider using ValueTask<T> as the exchange type, not Task<T> . 但是:如果您正在设计一个需要允许异步使用但实际上可能同步的接口:请考虑使用ValueTask<T>作为交换类型,而不是Task<T>

The generated C# of: 生成的C#:

public async System.Threading.Tasks.Task<bool> Contains(string key, string scope)
{
    return false;
}

is something like: 是这样的:

[StructLayout(LayoutKind.Auto)]
[CompilerGenerated]
private struct <Contains>d__0 : IAsyncStateMachine
{
    public int <>1__state;

    public AsyncTaskMethodBuilder<bool> <>t__builder;

    private void MoveNext()
    {
        bool result;
        try
        {
            result = false;
        }
        catch (Exception exception)
        {
            <>1__state = -2;
            <>t__builder.SetException(exception);
            return;
        }
        <>1__state = -2;
        <>t__builder.SetResult(result);
    }

    void IAsyncStateMachine.MoveNext()
    {
        //ILSpy generated this explicit interface implementation from .override directive in MoveNext
        this.MoveNext();
    }

    [DebuggerHidden]
    private void SetStateMachine(IAsyncStateMachine stateMachine)
    {
        <>t__builder.SetStateMachine(stateMachine);
    }

    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
    {
        //ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
        this.SetStateMachine(stateMachine);
    }
}

[AsyncStateMachine(typeof(<Contains>d__0))]
public Task<bool> Contains(string key, string scope)
{
    <Contains>d__0 stateMachine = default(<Contains>d__0);
    stateMachine.<>t__builder = AsyncTaskMethodBuilder<bool>.Create();
    stateMachine.<>1__state = -1;
    AsyncTaskMethodBuilder<bool> <>t__builder = stateMachine.<>t__builder;
    <>t__builder.Start(ref stateMachine);
    return stateMachine.<>t__builder.Task;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM