C# 相同对象性能的嵌套锁

C# 相同对象性能的嵌套锁,c#,concurrency,C#,Concurrency,对同一对象使用嵌套锁是否会造成性能损失 假设我们有: public void AddRange(IEnumeratable<Item> items) { lock (_syncObject) { foreach (Item item in items) { InsertItem(item); } } }

对同一对象使用嵌套锁是否会造成性能损失

假设我们有:

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

    public void InsertItem(Item item)
    {
        lock (_syncObject)
        {
            //..
        }
    }
public void AddRange(IEnumeratable项)
{
锁定(_syncObject)
{
foreach(项目中的项目)
{
插入项(项目);
}
}
}
公共无效插入项(项)
{
锁定(_syncObject)
{
//..
}
}
在“性能方面”这样做可以吗


提前感谢。

不是免费的。它必须在返回之前检查某些东西。有多少事情以及它必须做什么,取决于实施情况。我猜这种用法很常见,MS为此用例做了一些优化

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

这是一个相当简单的测试用例,执行数百万个嵌套锁定(如您所建议的),并对其他锁执行相同的操作

另请注意,如果使用非嵌套锁,则可能会在要添加的范围中间获得一个对象:

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

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

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

public void InsertItem(Item item)
{
    AddRange(new IEnumeratable({item}))
}

public void AddRange(IEnumeratable<Item> items)
{
    lock (_syncObject)
    {
        foreach (Item item in items)
        {
            // Insert code ..
        }
    }
}
public void插入项(项)
{
AddRange(新的IEnumeratable({item}))
}
公共无效添加范围(IEnumeratable项)
{
锁定(_syncObject)
{
foreach(项目中的项目)
{
//插入代码。。
}
}
}
@AddRange(新的IEnumeratable({item})):
我不是语法wizkid,所以如果这不正确,请纠正我

锁是有代价的,我建议您实现如下代码:

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);
    }
}
public void AddRange(IEnumeratable项)
{
lock(\u syncObject)//只锁定一次。
{
foreach(项目中的项目)
{
InsertItemImpl(项目);
}
}
}
私有void InsertItemImpl(项)
{
//插入项目
}
公共无效插入项(项)
{
锁定(_syncObject)
{
InsertItemImpl(项目);
}
}

我认为最好将Insert实现转移到另一个方法,而不是为每个添加项创建新集合。