[英]Is making long-running calls async this simple?
我只是,为了粗略的草案,使用以下模式将大量数据访问方法转换为异步,并且它看起来太简单,不适合以后的迭代。 它有多安全,缺少什么,我应该怎么做?
提供长时间呼叫的服务:
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));
}
你不应该像这样做“假异步”方法:
public async Task<IdentityUser> GetByIdAsync(int id)
{
await Task.Run(() => _userService.GetById(id));
}
我称之为“假异步”的原因是因为没有任何关于操作的内在异步。 在这种情况下,您应该只有同步方法。 如果调用者想通过使用Task.Run
使其异步,他可以这样做。
什么时候本质上是异步的? 当您向Web服务或数据库发出请求时,例如,在发送请求和接收响应之间存在等待时间 - 请求是本质上异步操作。 要避免阻塞调用线程,请使用async-await。
从技术上讲,这是有效的,但它的工作原理是创建一个新线程来执行同步操作,该操作本身就是在一个固有的异步操作中进行包装和阻塞。 这意味着你没有从一开始就获得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()
用于固有的异步操作),这将允许系统在您等待数据库操作完成时释放当前线程。 该线程可以在其他地方重用,当操作完成后,您可以使用当时可用的任何线程。
它可能也值得阅读并采用这些最佳实践 。 例如,您可能希望在不访问会话和请求等上下文信息的任何地方使用.ConfigureAwait(false)
。
当然,这个答案假定GetById
本质上是异步的:您从硬盘驱动器或网络位置或其他东西检索它。 如果它使用长时间运行的CPU操作来计算用户的ID,那么Task.Run()
是一个很好的方法,你可能还想在Task.Run()
的参数中另外指定它是一个长时间运行的任务。 Task.Run()
。
Task.Run()只应用于受CPU限制的工作。 不记得为什么。 尝试改为使用GetByIdAsync()方法,最终调用异步资源。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.