【问题标题】:Nested lock to the same object performance嵌套锁到同一个对象的性能
【发布时间】:2010-04-22 15:41:34
【问题描述】:

对同一个对象使用嵌套锁是否会造成性能成本。

假设我们有:

    public void AddRange(IEnumeratable<Item> items)
    {
        lock (_syncObject)
        {
            foreach (Item item in items)
            {
                InsertItem(item);
            }
        }
    }

    public void InsertItem(Item item)
    {
        lock (_syncObject)
        {
            //..
        }
    }

“性能方面”可以这样做吗?

提前致谢。

【问题讨论】:

    标签: c# concurrency


    【解决方案1】:

    锁是有成本的,我建议你这样实现你的代码:

    public void AddRange(IEnumeratable<Item> items)
    {
        lock (_syncObject) // Locking only once.
        {
            foreach (Item item in items)
            {
                InsertItemImpl(item);
            }
        }
    }
    
    private void InsertItemImpl(Item item)
    {
         // inserting the item
    }
    
    public void InsertItem(Item item)
    {
        lock (_syncObject)
        {
            InsertItemImpl(item);
        }
    }
    

    【讨论】:

      【解决方案2】:

      lock 不是免费的。它必须在返回之前检查某些事情。有多少事情和它必须做什么,取决于实施。我这种用法很常见,MS 对这个用例做了一些优化。

      我仍然建议您单独实现 AddRange,一次性完成所有操作。这当然取决于类接口的其余部分(是否有侦听器,它们是否可以接收到添加了多个对象的消息等)。

      这是一个相当简单的测试用例,做几百万个嵌套锁定(你建议什么),对另一个锁也是如此。

      如果您使用非嵌套锁,请注意不同的可能顺序,您可能会在要添加的范围的中间得到一个对象:

      AddRange _sync1
        AddItem _sync2
        AddItem _sync2
        --- interruption, other thread calls:
        AddItem _sync2
        --- AddRange again:
        AddItem _sync2
      

      当与单个 _syncObject 同步时,没有人可以中断,因为锁已经被另一个线程持有。

      【讨论】:

        【解决方案3】:

        我不知道性能如何受到影响,但是当我们预计它会降低性能时,我建议您以相反的方式实现您的代码:

        public void InsertItem(Item item)
        {
            AddRange(new IEnumeratable({item}))
        }
        
        public void AddRange(IEnumeratable<Item> items)
        {
            lock (_syncObject)
            {
                foreach (Item item in items)
                {
                    // Insert code ..
                }
            }
        }
        

        @AddRange(new IEnumeratable({item})) : 我不是语法高手,如有不妥请指正!

        【讨论】:

        • 我认为最好将 Insert 实现移到另一个方法,而不是为每个添加项创建新集合。
        猜你喜欢
        • 2023-01-08
        • 2014-03-04
        • 1970-01-01
        • 1970-01-01
        • 2012-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多