我正在包装 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();
}
第二个例子:
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();
}
客户会这样调用它:
result = await _userManager.RemovePasswordAsync(user.Id);
我的第一个问题是:
当客户端调用第二个方法时,工作从 IO 线程卸载到线程池线程。当调用 RemovePasswordAsync
时,它会调用具有 await 关键字的 UpdateAsync
。那么,此时此线程池线程是否卸载到另一个线程池线程?还是 TPL 继续使用相同的线程?
我的第二个问题是;构造这个async
方法的第一个实现和第二个实现的主要区别是什么?
编辑:
这是 UserStore
类的更新方法。 (_store.UpdateAsync(用户)
)
public Task UpdateAsync(TUser user)
{
if (user == null)
throw new ArgumentNullException("user");
return _userService.UpdateAsync(user);
}
这是UserService
类的更新方法
public Task UpdateAsync(TUser user)
{
return Task.Factory.StartNew(() => Update(user));
}
最佳答案
我会回答你的第一个问题。
您误解了 async/await 的工作原理。
async
方法将同步运行至少,直到它遇到第一个await
语句。
当它遇到 await
时,它有两个选项:
- 如果可等待(例如
Task
)已经完成,则继续执行当前上下文(即 UI 线程或 ASP.NET 请求的上下文)。 - 如果 awaitable 尚未完成,它会包装方法主体的其余部分并安排在任务完成时在当前上下文(即 UI 线程)(*) 上执行。
根据这个定义,您的整个代码将在同一个 ASP.NET 请求的上下文中运行。
然而,_store.UpdateAsync
可能会产生一个 ThreadPool 线程(例如,通过使用 Task.Run
)。
已更新
根据您更新的答案,Update(user)
将在 ThreadPool 线程上运行。其他一切都将在当前上下文中运行。
(*) 如果没有同步上下文(即控制台应用程序),方法主体的其余部分将安排在 ThreadPool 线程上运行。
关于c# - 通过 await 关键字返回任务和不使用 await 关键字返回的主要区别是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22015164/