我想在多线程环境中测量并发字典与字典+锁的性能。因此,我创建了自己的<int,int[]>
类型的SyncDict类。只要存在键匹配,它就会向其自身添加int[]
数组值,并在更新值时使用ReaderWriterLockSlim锁定整个字典。
我通过并发字典复制了代码,主要使用AddOrUpdate()
方法。
整个控制台应用程序代码都可以在这里找到https://dotnetfiddle.net/1kFbGy,只需将代码复制粘贴到控制台应用程序中即可运行。它不会运行小提琴
在使用相同的输入运行两个代码之后,我发现运行时间有相当大的差异。例如,在我的计算机上进行一次特定的运行,并发字典花费了4.5秒,而SyncDict花费了不到1秒。
我想知道任何解释上述运行时间的想法/建议。我在这里做错什么吗?
class SyncDict<TKey>
{
private ReaderWriterLockSlim cacheLock;
private Dictionary<TKey, int[]> dictionary;
public SyncDict()
{
cacheLock = new ReaderWriterLockSlim();
dictionary = new Dictionary<TKey, int[]>();
}
public Dictionary<TKey, int[]> Dictionary
{
get { return dictionary; }
}
public int[] Read(TKey key)
{
cacheLock.EnterReadLock();
try
{
return dictionary[key];
}
finally
{
cacheLock.ExitReadLock();
}
}
public void Add(TKey key, int[] value)
{
cacheLock.EnterWriteLock();
try
{
dictionary.Add(key, value);
}
finally
{
cacheLock.ExitWriteLock();
}
}
public AddOrUpdateStatus AddOrUpdate(TKey key, int[] value)
{
cacheLock.EnterUpgradeableReadLock();
try
{
int[] result = null;
if (dictionary.TryGetValue(key, out result))
{
if (result == value)
return AddOrUpdateStatus.Unchanged;
else
{
cacheLock.EnterWriteLock();
try
{
Parallel.For(0, value.Length,
(i, state) =>
{
result[i] = result[i] + value[i];
});
}
finally
{
cacheLock.ExitWriteLock();
}
return AddOrUpdateStatus.Updated;
}
}
else
{
Add(key, value);
return AddOrUpdateStatus.Added;
}
}
finally
{
cacheLock.ExitUpgradeableReadLock();
}
}
public void Delete(TKey key)
{
cacheLock.EnterWriteLock();
try
{
dictionary.Remove(key);
}
finally
{
cacheLock.ExitWriteLock();
}
}
public enum AddOrUpdateStatus
{
Added,
Updated,
Unchanged
};
}
答案 0 :(得分:1)
your test存在多个问题。
1)您正在用约150.000个不同的键填充字典,所有键都具有相同的值。
2)所有条目的共享值是30.000个整数的数组,并且您在对AddOrUpdate
的调用的一半处更新了它的每个元素。但这仅在您测试ConcurrentDictionary
时发生。在SyncDict
测试中,条件if (result == value) return AddOrUpdateStatus.Unchanged
会跳过所有更新(因为该值是共享的)。
3)您正在使用不同的随机输入来输入两个测试。
4)您正在使用Parallel.For
循环更新数组,而同时已经在外部Parallel.For
循环中,从而使工作负载过分并行。
5)在调用方法 AddOrUpdate
时,您忽略了以下事实:updateValueFactory
函数以线程不安全的方式被调用,并且由于多个AddOrUpdate
是同步执行的并且该值是共享的,您正在破坏该值的状态。
在锁之外调用
updateValueFactory
委托,以避免在锁下执行未知代码可能引起的问题。
ConcurrentDictionary.AddOrUpdate Method
我建议您修改测试以反映ConcurrentDictionary
类的预期用途。