正在进行长时间运行的调用异步这么简单吗?

Pro*_*ofK 6 c# asynchronous async-await c#-5.0

我只是,为了粗略的草案,使用以下模式将大量数据访问方法转换为异步,并且它看起来太简单,不适合以后的迭代.它有多安全,缺少什么,我应该怎么做?

提供长时间呼叫的服务:

private class UserService
{
    public IdentityUser GetById(int id)
    {
        ...
    }
}

private UserService _userService = new UserService();
Run Code Online (Sandbox Code Playgroud)

原始的同步方法:

public IdentityUser GetById(int id)
{
    return _userService.GetById(id);
}
Run Code Online (Sandbox Code Playgroud)

我奇妙的新异步方法:

public async Task<IdentityUser> GetByIdAsync(int id)
{
    await Task.Run(() => _userService.GetById(id));
}
Run Code Online (Sandbox Code Playgroud)

Tim*_*lds 5

你不应该像这样做"假异步"方法:

public async Task<IdentityUser> GetByIdAsync(int id)
{
    await Task.Run(() => _userService.GetById(id));
}
Run Code Online (Sandbox Code Playgroud)

我称之为"假异步"的原因是因为没有任何关于操作的内在异步.在这种情况下,您应该只有同步方法.如果调用者希望通过使用使其异步Task.Run,他可以这样做.

什么时候本质上是异步的?当您向Web服务或数据库发出请求时,例如,在发送请求和接收响应之间存在等待时间 - 请求是本质上异步操作.要避免阻塞调用线程,请使用async-await.

  • @ProfK,然后将其实现为返回`Task.FromResult`并且不使用`async`关键字(无论如何都不是编译方法签名的一部分). (2认同)

Str*_*ior 1

从技术上讲,这是可行的,但它的工作原理是创建一个新线程来执行同步操作,该操作本身会包装并阻塞固有的异步操作。async这意味着您一开始就没有获得一些最大的好处。

正确的方法是全程异步。而现在你可能有这样的事情:

private class UserService
{
    public IdentityUser GetById(int id)
    {
        return mContext.Users.Single(u => u.Id == id);
    }
}
Run Code Online (Sandbox Code Playgroud)

...您现在应该创建一个异步版本:

private class UserService
{
    public async Task<IdentityUser> GetByIdAsync(int id)
    {
        return await mContext.Users.SingleAsync(u => u.Id == id);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

public async Task<IdentityUser> GetByIdAsync(int id)
{
    return await _userService.GetByIdAsync(id);
}
Run Code Online (Sandbox Code Playgroud)

当然,假设您的底层框架支持异步方法(例如SingleAsync()本质上的异步操作),这将允许系统在您等待数据库操作完成时释放当前线程。该线程可以在其他地方重用,并且当操作完成时,您可以使用当时可用的任何线程。

也许也值得阅读并采用这些最佳实践.ConfigureAwait(false)例如,您可能希望在不访问上下文信息(例如会话和请求)的任何地方使用。

当然,这个答案假设这GetById本质上是异步的:您从硬盘驱动器或网络位置或其他东西检索它。如果它使用长时间运行的 CPU 操作来计算用户的 ID,那么这Task.Run()是一个好方法,并且您可能需要在 的参数中额外指定它是一个长时间运行的任务Task.Run()