【问题标题】:Alternative to a monitor to checking for the existence of a record, and writing it if it doesn't exist替代监视器来检查记录是否存在,如果不存在则写入
【发布时间】:2023-03-15 22:41:01
【问题描述】:

所以我有一些如下所示的 C# 代码(出于问题的目的进行了简化,任何错误都是我进行这些更改的结果)。可以从多个线程或上下文以异步方式调用此代码。这样做的全部目的是确保如果记录已经存在,则使用它,如果不存在,则创建它。可能是也可能不是很好的设计,但这可以按预期工作。

var timeout = TimeSpan.FromMilliseconds(500);
bool lockTaken = false;

try
{
    Monitor.TryEnter(m_lock, timeout, ref lockTaken);  // m_lock declared statically above
    if (lockTaken)
    {
        var myDBRecord = _DBContext.MyClass.SingleOrDefault(x => x.ForeignKeyId1 == ForeignKeyId1
                                                              && x.ForeignKeyId2 == ForeignKeyId2);
        
        if (myDBRecord == null)
        {
           myDBRecord = new MyClass
           {    
                ForeignKeyId1 == ForeignKeyId1,
                ForeignKeyId2 == ForeignKeyId2
                // ...datapoints
           };
           _DBContext.MyClass.Add(myDBRecord);
           _DBContext.SaveChanges();
       }
   }
   else
   {
       throw new Exception("Can't get lock");
   }
}
finally
{
   if (lockTaken)
   {
       Monitor.Exit(m_lock);
   }
}

如果有很多请求进来,就会出现问题,它可能会使监视器不堪重负,如果它必须等待太久就会超时。虽然锁定的超时时间当然可以更短,但解决此类问题的首选方法是什么(如果有的话)?任何试图查看是否需要输入监视器的代码都需要成为该原子操作的一部分。

【问题讨论】:

  • WRT “很多请求进来”我们在谈论什么数字?
  • @DaleK 不幸的是,除了每秒说出多个请求外,我无法告诉您。我可以降低监视器的超时时间,但在某些时候,如果请求的进入速度比发出的速度快,一些请求会掉到地板上。也许这是不可避免的。
  • 好吧,如果您不确定,这有点难以建议 - 为什么不记录它呢?每秒多个请求不算什么...但也许您的代码很慢?您需要对要满足的需求有所了解,才能提出最佳解决方案。您还需要了解处理请求需要多长时间。因为分配一条记录应该是微不足道的。
  • 这个逻辑是否应该存在于数据库层中?
  • 网站中的这种逻辑看起来很奇怪,因为锁定在部署期间或如果有网络农场/花园时不起作用。

标签: c# sql-server asp.net-core concurrency entity-framework-core


【解决方案1】:

我建议您完全摆脱监视器,而是处理重复键异常。无论如何,您必须处理尝试输入重复值的情况,为什么不直接这样做呢?

【讨论】:

    猜你喜欢
    • 2016-01-06
    • 2021-03-29
    • 2012-05-09
    • 1970-01-01
    • 2018-03-31
    • 2011-05-12
    • 1970-01-01
    相关资源
    最近更新 更多