C# 如何使用缓存密钥锁定?

C# 如何使用缓存密钥锁定?,c#,asp.net,caching,locking,thread-safety,C#,Asp.net,Caching,Locking,Thread Safety,我正在尝试实现一个通用的线程安全缓存方法,我想知道应该如何在其中实现锁 它应该是这样的: //私有静态只读锁对象=新对象(); 公共T GetCache(字符串键、函数值工厂…) { //尝试从这里的缓存中提取 lock(lockObject)//我不想在这里使用静态对象锁,因为每次执行锁时,我站点中的所有缓存对象都必须等待,这与缓存密钥有关。 { //在我们拿到锁之前,缓存是空的,再次检查锁内部 //缓存仍然为空,因此请在此处检索该值 //将值存储在此处的缓存中 } //在此处返回缓存的值 }

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

它应该是这样的:

//私有静态只读锁对象=新对象();
公共T GetCache(字符串键、函数值工厂…)
{
//尝试从这里的缓存中提取
lock(lockObject)//我不想在这里使用静态对象锁,因为每次执行锁时,我站点中的所有缓存对象都必须等待,这与缓存密钥有关。
{
//在我们拿到锁之前,缓存是空的,再次检查锁内部
//缓存仍然为空,因此请在此处检索该值
//将值存储在此处的缓存中
}
//在此处返回缓存的值
}
用于池之间的非共享数据 当您有许多池(web garden)时,每个池都可以有它们的静态数据。这几天我在那里测量到,
ConcurrentDictionary
的速度更快,因为他们实现了某种不使用“内部查看”的技术,所以他们让它变得非常快

因此,对于池之间的非共享数据,我建议使用
ConcurrentDictionary

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

池之间的公共资源发生变化 现在,当您拥有在池之间共享的资源时,您需要使用互斥。例如,如果您试图从多个线程保存一个文件,或者打开一个文件以从多个线程对其进行更改,那么您需要使用互斥来同步该公共资源

因此,对于公共资源,您可以使用
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();
    }   
}
public T GetCache(字符串键,Func valueFactory…)
{
//这里请注意,我使用键作为互斥体的名称
//这里还需要检查密钥是否没有无效字符
//用作互斥体名称。
var mut=新的互斥锁(true,key);
尝试
{   
//等到安全时再进去。
mut.WaitOne();
//您可以在这里创建缓存
}
最后
{
//释放互斥锁。
mut.ReleaseMutex();
}   
}
什么样的锁 我们有两个锁箱

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

  • 第二种情况是,当我们使用仅对池内部可见的变量时,不同的池无法看到这些资源。例如,一个静态列表、一个静态字典等。这些静态变量、数组只能在池内访问,而在不同的池中它们是不同的
  • 在第二种情况下,lock()是最简单、最常用的使用方法

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

    您可以在此举一个完整的示例:

    使用ReaderWriterLockSlim,我们可以在不需要锁的时候避免锁,也不需要在只读时锁定静态值。所以我可以建议将静态值用作缓存

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

    所以,如果您有许多池(web garden)来同步它们以获得公共资源,那么您需要互斥。要在内部同步它们,请使用lock



    通过为每个密钥散列创建单独的锁,.NET
    ConcurrentDictionary
    在内部实现了这一点。这样做的好处是只锁定一个相关的散列,即使在处理项目添加和删除时也是如此。

    我刚刚找到了lib。但我还没有在生产中试用过

    IAppCache cache = new CachingService();
    ComplexObject cachedResults = cache.GetOrAdd("uniqueKey", 
        () => methodThatTakesTimeOrResources());
    

    你想达到什么目标?在我看来,您似乎混淆了两种类型的锁:一种是确保只有一个线程可以编辑缓存对象的锁,另一种是确保在缓存中添加/删除是线程安全的锁。为每个对象添加一个锁将帮助您确保只有一个线程可以更改它,但这与从缓存中添加/删除它无关(您没有提供这个实现,但我猜它将是某种字典)。我认为你无论如何也不能解除缓存收集级别锁定。我正在使用Asp.net缓存。。。所以我不必实现我自己的字典。。。我说的是锁定以添加。。。假设有1000人同时请求页面,我只希望其中一人缓存到对象,其他人都使用它……您仍然需要锁定基础集合,而不是对象。如果我理解正确,您要做的是检查对象是否不在此集合中,然后添加它。如果您使用的是.net 4,您可以使用它们的一个新阻止集合,例如ConcurrentDictionary,以确保每个密钥只添加一次。即使他需要任何类型的锁或同步对象,为什么他要使用互斥对象而不使用监视器?“互斥类使用的系统资源比监视器类多”(from)@YavgenyP有两个主要原因:1)锁定所有要使用/生成此缓存的线程,而只有一个线程。2) 只指定名称并锁定缓存的同一部分,而不是请求的每个缓存。-现在,我不知道他是否需要同步,我重播给他热做它,而不是争论他是否需要。感谢链接-我在生产中使用它,它的作品我们
    IAppCache cache = new CachingService();
    ComplexObject cachedResults = cache.GetOrAdd("uniqueKey", 
        () => methodThatTakesTimeOrResources());