简体   繁体   English

使用ASP.Net缓存确保线程安全-两种策略的故事

[英]Ensuring thread safety with ASP.Net cache - a tale of two strategies

I have code that is not currently thread safe: 我有当前不是线程安全的代码:

public byte[] GetImageByteArray(string filepath, string contentType, RImgOptions options)
{               
    //Our unique cache keys will be composed of both the image's filepath and the requested width
    var cacheKey = filepath + options.Width.ToString();
    var image = HttpContext.Current.Cache[cacheKey];

    //If there is nothing in the cache, we need to generate the image, insert it into the cache, and return it
    if (image == null)
    {
        RImgGenerator generator = new RImgGenerator();
        byte[] bytes = generator.GenerateImage(filepath, contentType, options);
        CacheItem(cacheKey, bytes);
        return bytes;
    }
    //Image already exists in cache, serve it up!
    else
    {
        return (byte[])image;
    }
}

My CacheItem() method checks to see if its max cache size has been reached, and if it has, it will start removing cached items: 我的CacheItem()方法检查是否已达到其最大缓存大小,如果达到了最大缓存大小,它将开始删除缓存的项目:

//If the cache exceeds its max allotment, we will remove items until it falls below the max
while ((int)cache[CACHE_SIZE] > RImgConfig.Settings.Profile.CacheSize * 1000 * 1000)
{
    var entries = (Dictionary<string, DateTime>)cache[CACHE_ENTRIES];
    var earliestCacheItem = entries.SingleOrDefault(kvp => kvp.Value == entries.Min(d => d.Value));
    int length = ((byte[])cache[earliestCacheItem.Key]).Length;
    cache.Remove(earliestCacheItem.Key);
    cache[CACHE_SIZE] = (int)cache[CACHE_SIZE] - length;
}

Since one thread could remove an item from the cache as another thread is referencing it, I can think of two options: 由于一个线程可以在另一个线程引用该项目时将其从缓存中删除,因此我可以想到两个选择:

Option 1: A lock 选项1:一把锁

lock (myLockObject)
{
    if(image == null){ **SNIP** }
}

Option 2: Assign a shallow copy to a local variable 选项2:将浅表副本分配给局部变量

var image = HttpContext.Current.Cache[cacheKey] != null ? HttpContext.Current.Cache[cacheKey].MemberwiseClone() : null;

Both of these options have overhead. 这两个选项都有开销。 The first forces threads to enter that code block one at a time. 第一个强制线程一次输入一个代码块。 The second necessitates creating a new object in memory which could be of non-trivial size. 第二个步骤需要在内存中创建一个新对象,该对象的大小可能不重要。

Are there any other strategies I could employ here? 我在这里可以采用其他策略吗?

To provide pure consistency of your cache solution you should lock your resource while slowing down the application. 为了提供缓存解决方案的纯粹一致性,您应该在降低应用程序速度的同时锁定资源。

In general, you should try to provide caching strategy, based on your application logic. 通常,您应该尝试根据应用程序逻辑提供缓存策略。

  • Check sliding window caching: while item which is older when some time span - will reduce locking of different threads - good when you have large spread of different cached items which not for sure will be used again. 检查滑动窗口缓存:当项目在某个时间段内较旧时-会减少不同线程的锁定-当大量不同的缓存项目散布而不确定不能再次使用时,则很好。
  • Consider using least frequently used strategy: the item that is least used should be removed while reached max cache size - best serves while you have multiple client hitting frequently same part of cached content. 考虑使用最不常用的策略:最不常用的项目应在达到最大缓存大小时被删除-当您有多个客户端频繁访问缓存内容的同一部分时,最有效的方法是服务。

Just check which one more suites better your type of BL and use it. 只需检查又一个套件更适合您的BL类型并使用它即可。 It will not remove the locking issue at all, but right choice will significantly remove racing conditions. 它根本不会消除锁定问题,但是正确的选择将极大地消除赛车状况。

In order to reduce shared resource between different threads, use read and write locks on each item and not on entire collection. 为了减少不同线程之间的共享资源,请对每个项目而不是整个集合使用读和写锁。 This will boost your performance as well. 这也将提高您的性能。

Another point of consideration that should be kept in mind - what if content of image with the same path is changed physically on the disk (different image was saved with the same name) while having this image already cached there is a chance of mistakenly provide not relevant data. 应该记住的另一点考虑-如果具有相同路径的图像的内容在磁盘上物理更改(不同的图像以相同的名称保存)而又已经缓存了该图像,则可能会错误地提供相关数据。

Hope it helped. 希望能有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM