c# - 如何通过缓存键锁定?

标签 c# asp.net caching locking thread-safety

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

它应该看起来像这样:

//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

}

最佳答案

对于池之间的非共享数据

当你有很多池(网络花园)时,每个池都可以有它们的静态数据。这几天我测量了ConcurrentDictionary<TKey, TItem>速度更快,因为他们实现了某种不使用内部查看的技术,因此他们使其速度极快。

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

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

池间公共(public)资源变化

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

因此对于公共(public)资源,您使用 mutex
Mutex 可以使用一个键来锁定基于该键的锁定 - 但您不能更改相同的资源!

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. 一种情况是我们在所有线程中使用所有池中的公共(public)资源。公共(public)资源可以是文件,也可以是数据库本身。

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

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

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

比锁更快

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

您可以从这里获取完整示例: ReaderWriterLockSlim

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

什么是 asp.net 中的池。

想象一下,不同的程序运行时彼此隔离,但服务于来自用户的传入请求。每个池子都有自己的世界,彼此之间没有交流。每个池都有自己的初始化、静态值和生命周期。要在池之间拥有一些公共(public)资源,您需要一些其他第三方程序,例如数据库、磁盘上的文件、服务。

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

IIS app pools, worker processes, app domains
Lifetime of ASP.NET Static Variable

关于c# - 如何通过缓存键锁定?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10714790/

相关文章:

c# - 使用 ffmpeg 和正则表达式获取 'location' 的视频

c# - Entity Framework 6.1 将 CommitFailureHandler 设置为事务处理程序导致 SQL Server 登录失败

c# - 访问用于绑定(bind) gridview 的数据或数据项

android - 将云端点模型类序列化到 Android 文件系统的方法

php - "Caching"所有用户的相同 MySQL 结果

c# - 处理数据时显示对话框

c# - 如何从 C# 应用程序远程调用另一个进程方法

javascript - 用于请求和响应的文件上传的 XHR 进度条

javascript - 从 View 中的 javascript 调用 Controller 操作

Android Volley Post 请求未发送到服务器且未刷新