21

我正在尝试实现一个通用的线程安全缓存方法,我想知道我应该如何在其中实现锁。

它应该看起来像这样:

//private static readonly lockObject = new Object();

public T GetCache<T>(string key, Func<T> valueFactory...)
{

  // try to pull from cache here

  lock (lockObject) // I don't want to use static object lock here because then every time a lock is performed, all cached objects in my site have to wait, regarding of the cache key.
  {
    // cache was empty before we got the lock, check again inside the lock

    // cache is still empty, so retreive the value here

    // store the value in the cache here
  }

  // return the cached value here

}
4

3 回答 3

7

对于池之间的非共享数据

当您有许多池(网络花园)时,每个池都可以拥有它们的静态数据。这几天我测量ConcurrentDictionary<TKey, TItem>到速度更快,因为他们实施了某种不使用内部查看的技术,所以他们让它变得非常快。

所以我建议ConcurrentDictionary<TKey, TItem>池之间的非共享数据。

在这种情况下,您必须注意自己的数据同步,以避免在同一数据上发生并发数据更改。在那里您可以使用 SlimLock 或 Lock。

池之间的公共资源变化

现在,当您拥有在池之间共享的资源时,您需要使用互斥锁。例如,如果您尝试从多个线程保存文件,或者打开一个文件以从多个线程更改它 - 您需要互斥锁来同步该公共资源

因此,对于使用互斥锁的公共资源,
Mutex可以使用 Key 来锁定基于该键的锁定 - 但您不能更改相同的资源!

public T GetCache<T>(string key, Func<T> valueFactory...) 
{
    // note here that I use the key as the name of the mutex
    // also here you need to check that the key have no invalid charater
    //   to used as mutex name.
    var mut = new Mutex(true, key);

    try
    {   
        // Wait until it is safe to enter.
        mut.WaitOne();

        // here you create your cache
    }
    finally
    {
        // Release the Mutex.
        mut.ReleaseMutex();
    }   
}

什么样的锁

我们有两个锁盒。

  1. 一种情况是当我们在所有池、所有线程中使用公共资源时。公共资源可以是文件,也可以是数据库本身。

在公共资源中我们需要使用mutex

  1. 第二种情况是当我们使用仅对池内部可见的变量时 - 不同的池无法看到该资源。例如静态 List<>、静态 Dictionary 等。这个静态变量、数组只能在池内部访问,并且它们在不同的池中是不一样的。

在第二种情况下,lock()是最简单和最常用的方法。

比锁还快

现在,当我们有一个长期保存的静态字典并在那里进行太多读/写时,避免整个程序等待的更快方法是ReaderWriterLockSlim

你可以从这里举一个完整的例子:ReaderWriterLockSlim

使用 ReaderWriterLockSlim,我们可以在不需要它们时避免锁定 - 并且我们在读取时不需要锁定静态值 - 只有在我们写入它们时。所以我可以建议我们将它们用作缓存的静态值。

什么是 asp.net 中的池。

就像运行的不同程序相互隔离但为来自用户的传入请求提供服务。每个池子都有自己的世界,彼此之间没有交流。每个池都有它们的初始化、静态值和生命周期。要在池之间拥有一些公共资源,您需要一些其他的第三个程序,比如数据库、磁盘上的文件、服务。

因此,如果您有许多池(网络花园)来同步它们以获得公共资源,则您需要互斥锁。要在内部同步它们,请使用锁。

IIS 应用程序池、工作进程、应用程序域
ASP.NET 静态变量的生命周期

于 2012-05-23T07:39:29.163 回答
3

我刚刚找到了 LazyCache库。不过,我还没有在生产中尝试过。

IAppCache cache = new CachingService();
ComplexObject cachedResults = cache.GetOrAdd("uniqueKey", 
    () => methodThatTakesTimeOrResources());
于 2017-02-03T21:53:51.043 回答
0

.NETConcurrentDictionary<TKey, TItem>通过为每个密钥哈希创建单独的锁在内部实现这一点。这具有仅锁定一个相关哈希的好处,即使在处理项目添加和删除时也是如此。

于 2013-12-22T14:25:17.983 回答