异步函数可以在其另一个实例运行的同时运行吗?

时间:2016-09-09 16:17:21

标签: c# asp.net-mvc asp.net-core

所以我在一个注入控制器的单例服务中有这样的函数。

public async Task<ResponseModel> Put(BoardModel request)
{
    var board = await dbService.GetBoardAsync(request.UserId, request.TargetId, request.Ticker);

    // Update the model
    // ...

    var response = await dbService.SetBoardAsync(request.UserId, request.TargetId, request.Ticker, request);

    return new ResponseModel
    {
        ResponseStatus = response.Successful(replacements: 1) ? ResponseStatus.Success : ResponseStatus.Failure
    };
}

我担心的是竞争条件,比如说该函数的两个实例同时运行,并且一个覆盖数据库中的条目。

这可能吗?它发生的可能性非常小,但我仍然有点担心。

谢谢!

1 个答案:

答案 0 :(得分:1)

是的,假设您的服务器有多个线程(可以是任何支持生产的Web服务器),那么两个或多个线程可以同时运行相同的代码块。处理这种情况的典型方法是乐观并发。这意味着EF将尝试保存记录(乐观地假设它能够没有问题),并且如果记录最终在它到达之前被修改,它将返回例外(特别是OptimisticConcurrencyException)。您可以查看this ASP.NET getting started article以了解如何设置它的演练。本质上,它只涉及向数据库表添加rowversion列。每次更新行时,该列的值都会发生变化。因此,EF可以检查其尝试使用当前桌面上的内容进行更新的记录上的值。如果它们相同,则可以继续更新。如果没有,那么其他东西修改了记录并停止更新。通过捕获返回的异常,您可以通过重新加载数据并尝试进行另一次更新来做出适当的响应。

你最不可能会多次遇到并发问题,但为了以防万一,我建议使用类似PollyNuget)之类的东西来处理异常。除此之外,它允许您重试一定次数甚至永远,直到没有异常引发。这样就可以确保记录最终得到更新,即使存在多个并发冲突。

Policy
  .Handle<OptimisticConcurrencyException>()
  .RetryForever((exception, context) => {
      // resolve concurrency issue
      // See: https://msdn.microsoft.com/en-us/data/jj592904.aspx
  })
  .Execute(() => {
      db.SaveChanges();
  });