簡體   English   中英

用於頻繁讀取和罕見寫入操作的並發收集(.NET)

[英]Concurrent collection to use for frequent read and rare write operations (.NET)

我想在我的Web應用程序中創建一個緩存,這將允許頂層(MVC)持久保存從底層(服務和數據庫)檢索的某些值,以避免對它的不必要的請求。 我希望在網站的每個頁面上存儲我想要存儲在緩存中的數據,因此該緩存旨在顯着減少請求量。 這個想法是很多線程將從集合中讀取數據,而一個線程將清除它並在緩存過期后檢索新數據。 這意味着該集合將用於頻繁閱讀罕見的書寫操作。

對我來說,問題是為這些目的選擇合適的類。 我已經閱讀了.NET 4中引入的System.Collections.Concurrent的並發類集。我絕對不需要使用ConcurrentQueueConcurrentStack ,但我必須在BlockingCollectionConcurrentBagConcurrentDictionary之間進行選擇。

在這種情況下, ConcurrentBag似乎是最好的解決方案。 但是,我在這篇文章中讀到了並發字典

...對於讀取操作完全沒有鎖定。 通過這種方式,它針對從字典中讀取最頻繁操作的情況進行了優化。

那么最好的解決方案是使用ConcurrentDictionary<int, MyTypeOfObj>嗎? 或者我可能根本不需要並發類型,簡單的List會完成這項工作嗎? 可能,如果我可以以某種方式鎖定緩存更新時的操作,它會這樣做。 但是使用簡單的lock是不可取的。

任何建議和解釋都表示贊賞。

更新

緩存用於存儲插座的地圖點。 這組插座非常穩定,但應該有一個UI來添加它們,因此插入操作非常少見。 在超時后從底層執行整個集合然后執行插入操作可能更容易。 也不需要搜索,閱讀意味着簡單的枚舉。

根據對問題的評論,我決定使用MemoryCache (事實上​​,我並不是很清楚)。 由於我不需要為數據分離緩存實例,因此我使用保存在Default屬性中的緩存:

除非需要,否則不要創建MemoryCache實例。 (...)如果在應用程序中只創建一個緩存實例,請使用默認緩存,並在需要訪問緩存時從Default屬性獲取對它的引用。

鏈接(MSDN)

我通過以下方式初始化緩存:

private static MemoryCache _instance = MemoryCache.Default;

public static IEnumerable<MyDto> GetDtos()
{
    var result = _instance.Get(SOME_NAME);
    if (result == null)
        result = InitializeCache();
    return result;
}

沒有用於閱讀操作的鎖。 然后,在InitializeCache鎖定一個以防止多個請求:

private static IEnumerable<MyDto> InitializeCache()
{
    lock (_monitor) // here all threads but one will stop
    {
        var result = _instance.Get(SOME_NAME); // in case this thread is not the first who entered the lock
        if (result == null)
        {
            result = RetrieveSomeHowYourDataFromDbOrService();
            if (result == null)
                return null; // or exception
            _instance.Set(SOME_NAME, result, new CacheItemPolicy { AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(TIMEOUT)), RemovedCallback = CacheClearedCallback}); 
        }
        return (IEnumerable<MyDto>)result;
    }
}

使用CacheItemPolicy允許清除過時的項目並從回調中再次檢索項目:

private static void CacheClearedCallback(CacheEntryRemovedArguments arguments)
{
    InitializeCache();
}

在這種情況下,緩存將在沒有來自消費者的請求的情況下進行更新(而不是在應用程序中的第一個請求中進行)。

可能,這不是有史以來最好的解決方案,但希望可以幫助某人,也許可以從一開始。 感謝您提示和評論。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM