【问题标题】:Handling concurrency at group level rather than application level在组级别而不是应用程序级别处理并发
【发布时间】:2020-03-02 22:36:06
【问题描述】:

我想处理 API 中的并发问题。在这种情况下,我们收到来自多个用户对同一组的请求。也可以有多个组。下面的解决方案我认为应该有效,纠正我

 // This will be a singleton across the API
 ConcurrentDictionary<string, string> dict = new ConcurrentDictionary<string, string>();

 if (dict.ContainsKey(groupId)) {
    throw new Exception("request already accepted");
 } else {
     // Thinking this is thread lock operation or i can put lock statement
     if(dict.TryAdd(groupId, "Added") == false) {
        throw new Exception("request already accepted");
     }
     // continue the original logic
 }

每 10 分钟后,我们将清除字典中的旧键(注意此操作应该正常工作,即线程未锁定模式,因为它将在已使用的旧键上工作)。并发字典是否在键级别而不是字典级别具有线程锁定?这样我们就不会阻止所有请求,而是仅阻止与组相关的特定请求。非常感谢任何帮助。

一个快速的解决方案是在字典操作的getadd 周围使用锁定包装器,但这会阻止所有请求继续进行,我们希望在组级别阻止。非常感谢任何帮助。

【问题讨论】:

  • 线程安全集合保证其内部数据结构始终有效,即使从多个线程访问也是如此。线程安全集合不保证线程上的顺序操作都在其内部数据结构的相同“快照”上工作。根据这个定义,它不会锁定字典,它也不会阻止你的自己在脚上开枪。但是,它确实具有同步功能,可能会导致某些调用或过时的快照产生副作用
  • ConcurrentDictionary 仅确保您不会破坏容器状态。这不会自动使您自己的代码安全。事实并非如此,另一个线程可能会在 ContainsKey() 检查之后,在 TryAdd() 之前添加密钥。只是不要使用 ContainsKey(),没有必要。

标签: c# multithreading concurrency


【解决方案1】:

将内容添加到并发字典中是一项非常快速的操作。您也不会让线程等待第一个线程完成,如果它们无法获取锁,您将立即扔掉。

这让我觉得你的情况可能并不真正需要 Double Checked Lock

所以,我会简单地做你的内部检查而不是外部检查:




if(dict.TryAdd(groupId, "Added") == false) 
{
        throw new Exception("request already accepted");
}

如果你在第一个请求之后有太多的请求,那么我会做你所做的,因为 ContainsKey will not lock

另一个有趣的话题是你将如何清理它。

也许您可以在 IDisposable 对象中执行所有这些锁定操作,该对象可以在处置时自行移除。例如:

// NOTE: THIS IS JUST PSEUDOCODE

// In your controller, you can simply do this...
//
public SomeController()
{

    using (var operation = new GroupOperation(groupId)) 
    {
        // In here I am sure I am the only operation of this group
    } 

    // In here I am sure that the operation got removed from the dictionary

}


// This class hides all the complexity of the concurrent dictionary
//
public class GroupOperation : IDisposable
{
    var singletonDictionary = new ConcurrentDictionary<int,int>()
    int GroupId;

    public GroupOperation(int GroupID)
    {
         this.GroupId = GroupId;
         if(!singletonDictionary.TryADd(GroupID, 1))
         {
             throw new Exception("Sorry, operation in progress for your group");
         }
    }

    protected virtual void Dispose(bool disposing)
    {
       singletonDictionary.Remove(GroupId)
    }
}


【讨论】:

    猜你喜欢
    • 2018-07-21
    • 2010-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-28
    相关资源
    最近更新 更多