Microsoft.AspNetCore.Identity UserManager GetUserAsync

时间:2016-08-08 12:03:42

标签: asp.net async-await task-parallel-library asp.net-identity

我一直在阅读UserManager.cs的源代码,并且我已经进入了以下块:

        public virtual Task<TUser> GetUserAsync(ClaimsPrincipal principal)
    {
        if (principal == null)
        {
            throw new ArgumentNullException(nameof(principal));
        }
        var id = GetUserId(principal);
        return id == null ? Task.FromResult<TUser>(null) : FindByIdAsync(id);
    }

如果上述原因不是这样的话,我一直非常好奇:

        public virtual async Task<TUser> GetUserAsync(ClaimsPrincipal principal)
    {
        if (principal == null)
        {
            throw new ArgumentNullException(nameof(principal));
        }
        var id = GetUserId(principal);
        return id == null ? await Task.FromResult<TUser>(null) : await FindByIdAsync(id);
    }

如您所见,我只添加了async / await。

*我正在用另一个ORM实现UserManager类。

1 个答案:

答案 0 :(得分:4)

由于我没有写它,我无法确定。 ;)但我想它是关于return await - 反模式。

在GitHub上甚至存在问题,其中请求是Roslyn在编译时处理它。

Optimize an async method that ends "return await e" to be non-async "return e"

  

此优化将提高异步方法的性能   他们唯一的等待出现在最后。不是在生成调试代码时   不是嵌套在try块中。

引用他在damien_the_unbeliever

上发布的this question的优秀评论
  

await是一种暂停当前方法直到其他方式的方法   代码完成了它的工作。如果你的方法将要做的所有   它的恢复就是说&#34;我已经完成了#34;那么你为什么要去所有的   努力?话虽这么说,实际的反模式是return await if   这个方法中只有 await(就像在这里一样)并且它不是   在具有tryfinally块的using块内(在这种情况下)   返回后还有其他代码可以运行

使用await/async时,应该知道它产生的开销。

以这两个类为例:

public class BaseClass
{
    public async Task<int> GetIdAsync()
    {
        return await Task.Run(() => 100);
    }
}

public class Foo : BaseClass
{
    public Task<int> GetId()
    {
        return GetIdAsync();
    }
}


public class Bar : BaseClass
{
    public async Task<int> GetId()
    {
        return await GetIdAsync();
    }
}

如果您使用ILSpyBar反编译代码,则会显示如下内容:

public class Bar : BaseClass
{
    [DebuggerStepThrough, AsyncStateMachine(typeof(Bar.<GetId>d__0))]
    public Task<int> GetId()
    {
        Bar.<GetId>d__0 <GetId>d__ = new Bar.<GetId>d__0();
        <GetId>d__.<>4__this = this;
        <GetId>d__.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
        <GetId>d__.<>1__state = -1;
        AsyncTaskMethodBuilder<int> <>t__builder = <GetId>d__.<>t__builder;
        <>t__builder.Start<Bar.<GetId>d__0>(ref <GetId>d__);
        return <GetId>d__.<>t__builder.Task;
    }
}

虽然Foo看起来像这样:

public class Foo : BaseClass
{
    public Task<int> GetId()
    {
        return base.GetIdAsync();
    }
}

所以,总而言之,如果您只是从一个Task返回值,那么{I}真的没有理由await。相反,您应该返回Task并让来电者 await代替Task。等待Task扩展堆栈并创建一个仅对性能产生负面影响的开销。