ASP.Net缓存并锁定高流量网站

时间:2012-08-09 09:31:50

标签: asp.net caching locking

这是情景:

  • 主题A要求使用法语的所有书籍

  • 主题B要求使用阿拉伯语的所有书籍

如果线程A位于锁定区域,则线程B将在锁定区域外等待线程A完成。

因为代码中只有一个“地方”,主题B可以获取他的数据。

我想基于缓存中的Key进行锁定,这意味着:

if(Cache["BooksInFrench"] == null)
{
    lock("BooksInFrench")
    {
        if(Cache["BooksInFrench"] == null)
        {
        object d = GetFromDB();
        cache["BooksInFrench"] = d;
        }
}

同样适用于BooksInArabic等.... 所以这样,如果我有200个连接到我的网站 其中10人要求BookInFrench 其余的请求(BooksInArabic,BooksInHebrew .......)可以运行并获取他们的数据因为他们的请求不在锁中 区域。

我当前的代码如下所示: http://pastebin.com/LFhxgHDM

我认为双重锁定不是很好...... 你看到其他任何解决方案/改进吗?

1 个答案:

答案 0 :(得分:0)

它可能只是在您的示例伪代码中,但locking on objects is recommended over strings(因为较低级别的优化,如不可变共享字符串,规范版本等等 - 请参阅Locking by string. Is this safe/sane?)。

对于单个已知的lock

// In your class
private static readonly object BooksInFrenchLock= new object();
private const string BookInFrenchCacheKey = "BooksInFrench";

// In your cache block
if(Cache[BookInFrenchCacheKey] == null)
{
    lock(BooksInFrenchLock)
    {
        if(Cache[BookInFrenchCacheKey] == null)
        {
            object d = GetFromDB();
            Cache[BookInFrenchCacheKey] = d;
        }
}

为了从数据库中锁定多个对象,您可以使用ConcurrentDictionary而不是哈希表(如your pastebin code中所示) - 它将为您节省一个额外的“级别”锁定。神奇的事情发生在BookLocks.GetOrAdd(bookLanguage, s => new object())

// In your class
private static readonly ConcurrentDictionary<string, object> BookLocks =
    new ConcurrentDictionary<string, object>();

// In your cache block
string bookLanguage = formatAndCleanBookLanguageArgument();

if(Cache[bookLanguage] == null)
{
    object lockObject = BookLocks.GetOrAdd(bookLanguage, s => new object());

    lock(lockObject)
    {
        if(Cache[bookLanguage] == null)
        {
            object d = GetFromDB();
            Cache[bookLanguage] = d;
        }
}