C# 在两种不同的场景中锁定性能
我有一个类,有两个内联列表,包含1000多个元素,如下所示C# 在两种不同的场景中锁定性能,c#,multithreading,locking,thread-safety,C#,Multithreading,Locking,Thread Safety,我有一个类,有两个内联列表,包含1000多个元素,如下所示 public class A { private List<long> aList = new List<long>(); private List<long> bList = new List<long>(); void MethodThatUsesAList() { //Works with aList } void Meth
public class A
{
private List<long> aList = new List<long>();
private List<long> bList = new List<long>();
void MethodThatUsesAList()
{
//Works with aList
}
void MethodThatUsesBList()
{
//Works with bList
}
void MethodThatUsesBoth()
{
//Works with both lists
}
}
并在所有方法中锁定此对象,
或者在使用列表时锁定每个列表,
我的第一个问题是,哪种方法更可取?
在第二种情况下,像这样使用锁是性能问题吗
void MethodThatUsesBoth()
{
lock(aList){
lock(bList){
//Works with both lists
}
}
}
一般来说,我认为前者(一种未使用的互斥)是首选。这样做没有实际成本,而且很容易使后者出错,也很容易造成死锁
void MethodThatUsesBoth()
{
lock(((ICollection)aList).SyncRoot){
lock(((ICollection)bList).SyncRoot){
//Works with both lists
}
}
}
void MethodThatUsesAList()
{
lock(((ICollection)aList).SyncRoot){
}
}
void MethodThatUsesBList()
{
lock(((ICollection)bList).SyncRoot){
}
}
在您的另一种解决方案中,我认为这是不好的,因为您在仅处理aList时阻止了对bList的访问。这不是一个好的性能解决方案。这里有两个独立的问题:
- 是使用一个组合锁还是两个单独的锁
- 是使用单独的对象锁定还是列表本身(或其
s)SyncRoot
方法和使用列表的方法能够同时运行,则需要两个单独的锁。然后,您必须确保在任何时候获取这两个锁时,它们的获取顺序相同。这意味着对任何获取锁的方法中的所有代码进行推理:例如,您需要确保它不会调用另一个获取另一个锁的方法
如果您的特定场景不太可能因为所有方法都被运行它们的任何一个线程有效地为其他线程阻塞而受到太大影响,那么为了简单起见,我将使用单个锁
无论哪种情况,我个人都会选择“私有”锁,这是其他代码所不知道的。我发现这样编写的代码更容易推理。使用列表本身或同步根目录可能非常好,但我更喜欢考虑其他任何东西都无法获得的锁。但是互斥比.net中的监视器(换句话说是锁)慢,不是吗?对不起,我不是指字面的Sysytem.Threading.mutex类,只是逻辑概念。我的应用程序列表是字典。不幸的是,我改为列表是为了简单
void MethodThatUsesBoth()
{
lock(((ICollection)aList).SyncRoot){
lock(((ICollection)bList).SyncRoot){
//Works with both lists
}
}
}
void MethodThatUsesAList()
{
lock(((ICollection)aList).SyncRoot){
}
}
void MethodThatUsesBList()
{
lock(((ICollection)bList).SyncRoot){
}
}