我只是,粗略的草案,使用以下模式将大量数据访问方法转换为异步,并且它看起来太简单,不足以满足以后的迭代。它有多安全,缺少什么,我该怎么做?
提供长时间通话的服务:
private class UserService
{
public IdentityUser GetById(int id)
{
...
}
}
private UserService _userService = new UserService();
原始的同步方法:
public IdentityUser GetById(int id)
{
return _userService.GetById(id);
}
我出色的新异步方法:
public async Task<IdentityUser> GetByIdAsync(int id)
{
await Task.Run(() => _userService.GetById(id));
}
答案 0 :(得分:5)
你不应该犯&#34;假异步&#34;像这样的方法:
public async Task<IdentityUser> GetByIdAsync(int id)
{
await Task.Run(() => _userService.GetById(id));
}
我之所以称之为&#34;假异步&#34;是因为没有任何内在的异步操作。在这种情况下,您应该只有同步方法。如果调用者希望使用Task.Run
使其异步,则可以执行此操作。
什么时候本质上是异步的?当您向Web服务或数据库发出请求时,例如,在发送请求和接收响应之间存在等待时间 - 请求是本质上异步操作。要避免阻塞调用线程,请使用async-await。
答案 1 :(得分:2)
从技术上讲,这是有效的,但它的工作原理是创建一个新线程来执行同步操作,该操作本身就是在一个固有的异步操作中包装和阻塞。这意味着您首先获得async
的最大好处。
正确的方法是一路异步。现在你可能有这样的东西:
private class UserService
{
public IdentityUser GetById(int id)
{
return mContext.Users.Single(u => u.Id == id);
}
}
...您现在应该创建一个异步版本:
private class UserService
{
public async Task<IdentityUser> GetByIdAsync(int id)
{
return await mContext.Users.SingleAsync(u => u.Id == id);
}
}
用法:
public async Task<IdentityUser> GetByIdAsync(int id)
{
return await _userService.GetByIdAsync(id);
}
当然,假设您的底层框架支持SingleAsync()
等异步方法用于固有的异步操作,这将允许系统在您等待数据库操作完成时释放当前线程。该线程可以在其他地方重用,当操作完成后,您可以使用当时可用的任何线程。
它可能也值得一读并采用these Best Practices。您可能希望在任何您未访问会话和请求等上下文信息的地方使用.ConfigureAwait(false)
。
当然,这个答案假设GetById
本质上是异步的:您从硬盘驱动器或网络位置或其他地方检索它。如果它使用长时间运行的CPU操作来计算用户的ID,那么Task.Run()
是一个很好的方法,你可能还想另外指定它&#39} ; Task.Run()
的参数中长期运行的任务。
答案 2 :(得分:0)
Task.Run()只应用于受CPU限制的工作。不记得为什么。 尝试改为使用GetByIdAsync()方法,最终调用异步资源。