静态查找字典上的锁定性能
本文关键字:锁定 性能 查找 字典 静态 | 更新日期: 2023-09-27 18:08:49
我有一个静态字典,我想用它作为ASP的内部缓存。网络应用程序。读的数量将大大超过写的数量,我希望确保以线程安全的方式执行此操作,而不会因不必要的锁而损害性能。
我有两个实现-第一个使用简单的锁对象和lock
键,第二个使用ReadWriteLockSlim
。
public class ConcurrentCache
{
private static readonly object LocationsLock = new object();
private static bool _locationsLoaded = false;
private static readonly ConcurrentDictionary<long, Location> Locations =
new ConcurrentDictionary<long, Location>();
public Location Get(long id)
{
EnsureLocationsDictionaryIsPopulated();
return Locations[id];
}
private void EnsureLocationsDictionaryIsPopulated()
{
if (Locations.Count > 0 || _locationsLoaded) return;
// Still locking, even though I'm using a ConcurrentDictionary,
// so that all locations are loaded only once and I don't have
// to worry about locking the reads.
lock (LocationsLock)
{
if (Locations.Count > 0 || _locationsLoaded) return;
PopulateLocationsDictionary();
_locationsLoaded = true;
}
}
// see below for other methods
}
ReadWriteLockSlim锁定
public class ReadWriteCache
{
private static readonly ReaderWriterLockSlim LockSlim =
new ReaderWriterLockSlim();
private static bool _locationsLoaded = false;
private static readonly Dictionary<long, Location> Locations =
new Dictionary<long, Location>();
public Location Get(long id)
{
EnsureLocationsDictionaryIsPopulated();
return Locations[id];
}
private void EnsureLocationsDictionaryIsPopulated()
{
if (Locations.Count > 0 || _locationsLoaded) return;
LockSlim.EnterWriteLock();
try
{
if (Locations.Count > 0 || _locationsLoaded) return;
PopulateLocationsDictionary();
_locationsLoaded = true;
}
finally
{
LockSlim.ExitWriteLock();
}
}
// see below for other methods
}
两个类都有相同的两个方法:
private void PopulateLocationsDictionary()
{
var items = LoadAllLocationsFromExternalSource();
if (items == null || items.Count == 0) return;
for (int i = 0; i < items.Count; i++)
{
var location = items[i];
Locations[location.Id] = location;
}
}
/// <summary>
/// This method actually calls an external API and takes
/// at least 5 seconds to run.
/// </summary>
/// <returns></returns>
private List<Location> LoadAllLocationsFromExternalSource()
{
return new List<Location>
{
new Location
{Id = 5, Value1 = "one", Value2 = "two", Value3 = "three"},
new Location
{Id = 10, Value1 = "I", Value2 = "II", Value3 = "III"},
new Location
{Id = 42, Value1 = "un", Value2 = "deux", Value3 = "trois"}
};
}
我从这篇文章(什么时候ReaderWriterLockSlim比一个简单的锁更好?)中看到,当访问模式主要涉及读时,ReadWriteLockSlim
预计会优于标准锁。在我的两种情况下仍然是这样吗?ReadWriteLockSlim
与ConcurrentDictionary
相比如何?还有什么我没考虑到的吗?
我建议使用最简单的方法(在本例中只是一个没有附加锁的ConcurrentDictionary
)。ConcurrentDictionary
类正是为您所想到的而设计的。
那么我建议通过IDictionary
接口将缓存暴露给外部世界。
如果将来在该区域出现性能问题(不太可能,瓶颈通常不在您期望的地方),您只需更改这一段代码,而应用程序的其余部分不会受到影响。
您可能会落入过早优化的陷阱,这是一个巨大的生产力和可维护性杀手。
如果您真的想知道哪一个更快,设置一个测试应用程序,并配置两种不同负载的情况。你会得到一个更准确的答案,为您的具体情况比我们将能够给你的堆栈溢出!