【问题标题】:Async Await with Task.Run method for DB call用于 DB 调用的带有 Task.Run 方法的异步等待
【发布时间】:2020-03-17 16:19:29
【问题描述】:

我们有一个 async/await 方法 GetLoanDataAsync,它通过实体框架调用存储过程,该实体框架由同步方法 GetData 调用。

GetLoanData 需要大量时间来执行,这可能是我们写成 async/await 的原因,它可以被多个地方使用。

我知道我们不应该混合使用异步和同步调用,但是假设我们有这种情况并且我们正在使用 Task.Run() 从同步方法 GetLoanDataAsync 调用异步方法 GetLoanDataAsync 我理解该方法 - @ 987654328@ 将在后台线程上运行。

我的问题是,如果我们有一个同步版本的异步方法 GetLoanDataAsync 并使用 Task.Run()GetData 调用,那么在这种情况下会有什么不同?

提供有关该问题的更多详细信息-

我们有返回类型不是任务的 ASP.NET REST Web API。这是从角度应用程序调用的。这个 api 有几个称为 GetData() 的方法,我们在其中等待来自GetLoanDataAsync 的结果。据我了解,GetLoanDataAsync 将在后台线程中被调用,并且能够执行GetUserDetails(),一旦完成,它将返回执行GetLoanDataAsync 的结果。

代码-

public List<int> GetData(int id)
{

    // Calls GetLoanDataAsync

    var result = Task.Run(()=> GetLoanDataAsync(id));

    // calls couple other sync methods

    GetUserDetails(); 

    return result.GetAwaiter().GetResult();

}

GetLoanDataAsync().Result 将导致死锁,这是较早的问题。为了解决这个问题,我们暂时尝试使用 Task.Run,​​直到我们将整个 api 设为异步。

【问题讨论】:

  • 你如何处理Task.Run()的结果?你等待任务完成吗?如果是,那么这与首先使用同步版本并没有什么不同。
  • 这是什么应用?网络?窗体?服务?
  • 记住异步 != 并行。异步意味着线程在等待时被释放。并行意味着同时发生两件或多件事情(在不同的线程上)。 Task.Run 将把它放在不同的线程上。由于它是一个异步方法,waiting happens nowhere.
  • 查看实际代码会有所帮助。 GetData 是什么样的?它是怎么称呼的?它是什么类型的应用程序(桌面、Web 等)?
  • 如果这是在 Web 上下文中,这是个坏主意,因为 ASP.NET 的线程池有限,Task.Run() 将占用其中一个宝贵的线程。如果数据库调用是真正异步的,并且您是从同步/阻塞线程调用它,那么最好的选择是说var result = GetLoanDataAsync().Result

标签: c# asynchronous async-await task


【解决方案1】:

如果您比较同步版本与异步版本,那么最明显的区别是同步版本在 DB 调用期间占用了一个线程,如果所有工作都在数据库中,这似乎是不必要的。这是否是一个问题取决于您的吞吐量。

通过使用Task.Run,您允许该操作与其他工作并行运行。这很好,只要您没有任何影响线程安全或依赖于单个逻辑执行流的接触点。

如果您想有效地使用异步,最好将其视为“粘性” - 即如果 X 是异步的,那么所有调用 X(直接或间接)的东西都需要是异步的。

【讨论】:

    猜你喜欢
    • 2015-09-28
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多