【问题标题】:Possible ways to do async over sync异步超过同步的可能方法
【发布时间】:2022-01-19 20:37:17
【问题描述】:

我有一个 ASP.NET API,它公开了一些数据库操作。 DB API 本身是同步的,无法更改。我知道在 ASP.NET 中使用 Task.Run 是一个坏主意,我打算使 Web API 同步,但开始考虑使数据库操作异步的不同可能方法,并想知道这些是否是个好主意.

  1. 使用Task.FromResult
[HttpGet]
public async Task<Result> Get()
{
      return Task.FromResult(DBOperation());
}

感觉除了结果之外,只分配Task 就好了。

  1. 使用ValueTask
return new ValueTask<Result>(DBOperation());

感觉和Task一样(只是分配更多)?不确定 ValueTask 是 struct 是更好还是更差。

  1. 使用TaskCompletionSource
public Task<Result> DBOperation()
{
    TaskCompletionSource<Result> tcs = new TaskCompletionSource<Result>();
    //db call
    tcs.SetResult(<result>);
    return tcs.Task;
}

不确定是否有帮助。

  1. 使用Task.Yield
public Task<Result> DBOperation()
{
    await Task.Yield();
    //db call
}

也许?

你怎么看?

【问题讨论】:

  • 基于Get() 上的[HttpGet] 属性我认为在这里引入异步而不是同步没有意义,只需将操作的返回类型更改为Result
  • 这些都是错误的,它们实际上是同步的。 Task.Run 实际上是一个更好的选择,我也不建议这样做,因为您可能会遇到跨多个线程访问数据库的并发问题。
  • 就像 2012 年的 Stephen Toub said:不要。
  • 只返回值。 Web 请求已经由单独的线程处理,因此所有选项都只会浪费 CPU 周期。如果 IO(在这种情况下是实际的数据库调用)可以异步执行,您只会从 async/await 获得一些东西。如果您的驱动程序不支持真正的异步,请寻找另一个或使用同步操作。例如,MySQL 的 Connector/NET 伪造异步调用,因此每个人都使用真正开源的MySQLConnector.Net
  • @dstr DB API itself is synchronous and can't be changed. 你确定吗?您正在调用什么数据库以及如何调用?可能有可以异步工作的替代驱动程序

标签: c# .net asp.net-core asynchronous async-await


【解决方案1】:

想知道这些是否是个好主意。

没有。

在 ASP.NET 上进行异步同步的每次尝试都会导致额外的内存开销。其中一些(Task.RunTask.Yield)还会导致额外的线程切换。

异步代码的全部意义在于释放线程,但如果你有一个不可避免的阻塞调用,那么线程不能根据定义被释放。正如 Panagiotis 指出的那样,您也许可以将阻塞调用替换为异步调用,但如果不能,那么 async-over-sync 将无济于事。

【讨论】:

    猜你喜欢
    • 2017-03-18
    • 2018-05-21
    • 2020-12-19
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多