嵌套锁定到相同的对象性能

时间:2010-04-22 15:41:34

标签: c# concurrency

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

说我们有:

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

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

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

提前致谢。

3 个答案:

答案 0 :(得分:7)

Lock有成本,我建议您实现这样的代码:

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);
    }
}

答案 1 :(得分:2)

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

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

这是一个相当简单的测试用例,做了数百万次嵌套锁定(你提出的建议)和其他锁定相同。

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

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

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

答案 2 :(得分:1)

我不知道性能会受到怎样的影响,但是当我们希望它降低性能时,我建议您反过来实现代码:

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})): 我不是一个语法wizkid所以请纠正我,如果这不对!