【问题标题】:EF Core async scalability in Asp.Net CoreAsp.Net Core 中的 EF Core 异步可扩展性
【发布时间】:2021-02-04 06:35:39
【问题描述】:

我知道 asp.net 控制器类中的这个动作方法只使用几个线程就可以处理数千个并发请求,即使_httpClient.GetAsync 需要很多秒才能返回。这是因为HttpClient.GetAsync()(在 Windows 中)使用 I/O 完成端口,并且在GetAsync() 返回之前没有线程正在运行。

[HttpGet]
public async Task<object> GetData()
{
    var result = await _httpClient.GetAsync("https://stackoverflow.com");
    return result.StatusCode;
}

但是我们可以对异步数据库操作说同样的话吗? EF Core 是否使用了一些无线程异步,或者会为每个 await SaveChangesAsync() 调用创建一个新线程?

[HttpPost]
public async Task<ActionResult<object>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();
    return ok;
}

当数据库在某个远程机器上时,它会利用一些套接字 IOCP,以便我们可以在更短的时间间隔内使用线程(仅适用于 db 中的非网络操作)?

如果在数据库操作的整个过程中都使用了一个新线程,那么我看不到任何 可扩展性 改进,因为对于每个请求,我都会完成启动 Controler/Action 的线程,而我只是开始一个新的(DB)。

在 Winforms 或 WPF 中,我们有一个可用性改进,因为 UI 需要保持响应,但在 Asp.Net Core 中没有 SynchronizationContext 或 UI 需要担心。

我看到 async/await 在 asp.net 核心中的更多地方使用(即 razor await Component.InvokeAsync),但它真的有用吗?

【问题讨论】:

  • 我想如果你想更多地了解具体的SaveChangesAsync,只要看看它的源代码。很难说它在幕后做了什么。 async 并不总是产生一个新线程,它取决于底层的任务调度程序。通常默认的 TaskScheduler 应该尽最大努力尽可能最有效地使用系统资源。很多开发人员并不真正需要关心它。最后,在尝试改进任何东西之前,您应该首先对所有内容进行基准测试以了解其性能是否足够。
  • HttpClient == 网络 (TCP)。数据库调用 == 网络(通常是 TCP)。你填补分歧?当然,这取决于 ADO.NET 提供程序的实现,但通常在 Windows 上,它们使用标准 TCP 类来建立连接。所以 IOCP 在这两种情况下都适用。

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


【解决方案1】:

但是我们可以对异步数据库操作说同样的话吗?

一般来说,是的。 HTTP 客户端和数据库查询都是基于 I/O 的操作,因此它们不需要本地线程就坐在那里等待响应。

EF Core 是否使用了一些无线程异步,或者会为每个 await SaveChangesAsync() 调用创建一个新线程?

具体实现取决于 EF Core DB 提供程序。这些天他们中的大多数是async,但也有一些值得注意的例外,比如 SQLite(可能还有 Oracle?我不记得了)。常见的 MSSQL 提供程序完全是 async,即不使用幕后的单独线程。

当数据库在某个远程机器上时,它会利用一些套接字 IOCP,以便我们可以在更短的时间间隔内使用线程(仅适用于 db 中的非网络操作)?

在客户端发送查询然后数据库响应结果的意义上,数据库查询类似于 HTTP。客户端没有任何“非网络操作”。

现在,如果您询问的是数据库服务器,那么这是一个实现细节,根本不会影响 EF Core(或任何其他数据库客户端)的运行方式。

如果在 DB 操作的整个过程中都使用了一个新线程,那么我看不到任何可伸缩性改进,因为对于每个请求,我都会完成启动 Controler/Action 的线程并且我只是启动一个新的 (DB) .

这正是在 ASP.NET 上不鼓励使用 Task.Run 的确切原因。

我看到 async/await 在 asp.net core 中的更多地方使用(即 razor await Component.InvokeAsync),但它真的有用吗?

在我看来,Razor 有点可疑,但这是从设计角度而非效率角度出发的。异步剃须刀允许页面本身执行查询数据库之类的操作。我更喜欢让动作执行所有异步工作并将视图模型传递给页面,然后同步呈现,因为所有数据都已经在内存中。但这只是设计偏好。

最后一点,网络服务器上的async 有助于您的网络服务器扩展。它根本不会改变您的数据库服务器的可伸缩性。如果您只有一个数据库服务器,那么允许您的 Web 服务器扩展可能不会给您带来任何可扩展性,因为您的瓶颈可能是您的数据库服务器。异步数据库调用主要受益于云数据库或数据库集群。也就是说,如果这是 开发,那么即使它不是瓶颈,也没有理由不使 Web 服务器异步。进一步讨论in this article

【讨论】:

    猜你喜欢
    • 2020-07-09
    • 1970-01-01
    • 2019-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多