对同一对象使用嵌套锁是否是性能成本。
说我们有:
public void AddRange(IEnumeratable<Item> items)
{
lock (_syncObject)
{
foreach (Item item in items)
{
InsertItem(item);
}
}
}
public void InsertItem(Item item)
{
lock (_syncObject)
{
//..
}
}
这样做“性能方面”可以吗?
提前致谢。
答案 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所以请纠正我,如果这不对!