【问题标题】:How does async prevent errors caused due to parallel execution?async 如何防止由于并行执行导致的错误?
【发布时间】:2022-01-13 03:16:51
【问题描述】:

使用 await 如何使代码线程安全?

链接:https://docs.microsoft.com/en-us/ef/core/dbcontext-configuration/#avoiding-dbcontext-threading-issues

Entity Framework Core 不支持多个并行操作 在同一个 DbContext 实例上运行。这包括并行 执行异步查询和任何显式并发使用 多个线程。因此,总是立即等待异步调用,或者 对执行的操作使用单独的 DbContext 实例 并行。

说 1 db 调用正在进行中,线程 1 正在上面。当它在其中工作时;

案例一:

假设我没有使用异步。另一个线程进行并行调用,因此会发生冲突和错误。

案例 2:

假设我使用异步。另一个线程进行了并行调用:

案例 2.a:由于我们使用异步,当第一个线程发出请求并等待响应时,它将释放线程,因此线程 2 在发出请求时不会发生冲突。我明白这一点。

案例 2.b 如果两个线程真的同时发出请求会怎样。

案例 2.b 是否可行,在这里使用 async 是否有帮助?

【问题讨论】:

  • 不能在同一个 DbContext 上执行并发操作。您不必这样做也没有意义:DbContext 是一个工作单元,而不是数据库连接。不要试图让它表现得像一个连接或强迫它同时做任何事情。如果某些操作很慢,请找出原因而不是尝试“并行化”它
  • 文档意味着实体框架支持异步操作,但不支持异步并行操作。因此,在实体框架的一个实例上一次运行一个异步操作并完成(等待位)实体框架实例上的任何其他类型的并行操作将引发异常
  • DbContext 是一个工作单元。这意味着对其跟踪的对象的任何修改不会持久化,也不会立即持久化。在请求/业务事务/工作结束时,对SaveChangesAsync单次 调用将为所有实体保留所有 未决更改。 SaveChangesAsync 实质上提交了工作单元。这比尝试坚持每个单独的更改要快很多
  • 换一种说法,DbContext 实例是一辆载有所有乘客(变更)到目的地(数据库)的公共汽车。你不能拆分那辆公共汽车。并且尝试为每位乘客使用公共汽车将比等待所有人上车要慢得多

标签: c# .net multithreading entity-framework .net-6.0


【解决方案1】:

“总是立即等待异步调用”意味着避免启动多个异步操作并等待它们稍后完成(就像对多个 HTTP 请求所做的那样)。

这是一个典型的例子,说明应该如何处理异步 HTTP 调用,但对 EF 操作无效:

// start operations early so results are there after our CPU intensive code complete 
var task1 = dbContext.GetSomething();
var task2 = dbContext.GetMore();
// do something slow here to let both operations to finish 
var result1 = await task1; 
// even more code
var result2 = await task2;

此代码将使两个操作并行运行,从而可能导致 dbContext 出现问题。

指南建议:

var result1 = await dbContext.GetSomething();
var result2 = await dbContext.GetMore();
// run slow code now sequntially to avoid parallel calls to dbContext.

确实,如果你小心的话,你可以对 DBContext 的调用和对不相关对象的其他操作进行类似的交错 - 即 HTTP 调用和 DBContext 并行调用,或者 DBContext 调用和 CPU 密集型代码与后期 awiat 并行运行EF 调用。

请注意,该指南对于在两个线程之间共享上下文没有多大帮助 - 与任何非线程安全对象一样,您有责任防止同时访问此类共享对象。

【讨论】:

    【解决方案2】:

    您缺少的是,在 ASP.NET Core 的常见情况下,DbContext 的范围仅限于 HTTP 请求,并且框架保证在任何时候都只会运行一个中间件或控制器方法来处理请求一度。所以awaiting 异步调用足以防止并行 DbContext 访问。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-11
      • 1970-01-01
      • 1970-01-01
      • 2013-04-26
      • 1970-01-01
      • 1970-01-01
      • 2012-08-13
      相关资源
      最近更新 更多