静态查找字典上的锁定性能

本文关键字:锁定 性能 查找 字典 静态 | 更新日期: 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预计会优于标准锁。在我的两种情况下仍然是这样吗?ReadWriteLockSlimConcurrentDictionary相比如何?还有什么我没考虑到的吗?

静态查找字典上的锁定性能

我建议使用最简单的方法(在本例中只是一个没有附加锁的ConcurrentDictionary)。ConcurrentDictionary类正是为您所想到的而设计的。

那么我建议通过IDictionary接口将缓存暴露给外部世界。

如果将来在该区域出现性能问题(不太可能,瓶颈通常不在您期望的地方),您只需更改这一段代码,而应用程序的其余部分不会受到影响。

您可能会落入过早优化的陷阱,这是一个巨大的生产力和可维护性杀手。

如果您真的想知道哪一个更快,设置一个测试应用程序,并配置两种不同负载的情况。你会得到一个更准确的答案,为您的具体情况比我们将能够给你的堆栈溢出!