通过await关键字返回任务与不使用await关键字返回之间的主要区别是什么?

Kem*_*kin 8 c# asp.net multithreading task-parallel-library

我正在包装AspNet.Identity.但有些事让我对TPL感到困惑.

第一个例子:

    public virtual async Task<IdentityResult> RemovePasswordAsync(string userId)
    {
        var user = _store.FindByIdAsync(userId).Result;
        if (user == null)
            throw new InstanceNotFoundException("user");

        user.PasswordHash = String.Empty;
        user.SecurityStamp = String.Empty;
        return await UpdateAsync(user);
    }

    public virtual async Task<IdentityResult> UpdateAsync(TUser user)
    {
        await _store.UpdateAsync(user);
        return new IdentityResult();
    }
Run Code Online (Sandbox Code Playgroud)

第二个例子:

    public virtual Task<IdentityResult> RemovePasswordAsync(string userId)
    {
        var user = _store.FindByIdAsync(userId).Result;
        if (user == null)
            throw new InstanceNotFoundException("user");

        user.PasswordHash = String.Empty;
        user.SecurityStamp = String.Empty;
        return UpdateAsync(user);
    }

    public virtual async Task<IdentityResult> UpdateAsync(TUser user)
    {
        await _store.UpdateAsync(user);
        return new IdentityResult();
    }
Run Code Online (Sandbox Code Playgroud)

客户会称之为:

    result = await _userManager.RemovePasswordAsync(user.Id);
Run Code Online (Sandbox Code Playgroud)

我的第一个问题是:

当客户端调用第二个方法时,工作将从IO线程卸载到线程池线程.当RemovePasswordAsync调用它时,调用UpdateAsync具有await关键字.那么,在这一点上,这个线程池线程是否会卸载到另一个线程池线程?或者TPL是否继续使用相同的线程?

我的第二个问题是; 构建此async方法的第一个实现和第二个实现之间的主要区别是什么?

编辑:

这是UserStore该类的更新方法.(_store.UpdateAsync(user))

    public Task UpdateAsync(TUser user)
    {
        if (user == null)
            throw new ArgumentNullException("user");

        return _userService.UpdateAsync(user);
    }
Run Code Online (Sandbox Code Playgroud)

这是UserService该类的更新方法

    public Task UpdateAsync(TUser user)
    {
        return Task.Factory.StartNew(() => Update(user));
    }
Run Code Online (Sandbox Code Playgroud)

dca*_*tro 3

我来回答你的第一个问题。

您误解了 async/await 的工作原理。

方法async将同步运行,至少直到它到达第一个await语句。当它点击 时await,它有两个选项:

  • 如果等待(例如Task)已经完成,则执行将在当前上下文(即 UI 线程或 ASP.NET 请求的上下文)中进行。
  • 如果等待尚未完成,它会包装方法主体的其余部分,并安排在任务完成时在当前上下文(即 UI 线程)(*) 上执行该方法。

根据此定义,您的整个代码将在同一 ASP.NET 请求的上下文中运行。

_store.UpdateAsync然而,可能会产生一个 ThreadPool 线程(例如,通过使用Task.Run)。

更新

根据您更新的答案,Update(user)将在 ThreadPool 线程上运行。其他一切都将在当前上下文中运行。


(*)如果没有同步上下文(即控制台应用程序),方法主体的其余部分将被安排在 ThreadPool 线程上运行。

  • @KemalGültekin 请注意,如果您这样做,您将实现并行性。您将同时执行“Update(user)”和“//...”。然而,您将“用可扩展性(您可以为多少个客户提供服务)来换取性能(您可以多快地将响应返回给单个客户)”(引自 [Brad Wilson](http://www.hanselman. com/blog/TheMagicOfUsingAsynchronousMethodsInASPNET45PlusAnImportantGotcha.aspx))。 (2认同)