2010-11-16 77 views
3

假設我有兩個線程(線程1,線程2),其中的螺紋是在同一時間訪問高速緩存給定對象,如在下面的代碼幾乎:緩存訪問

Dim expensiveToGetData = Cache("ExpensiveDataKey") 

    If ExpensiveToGetData is nothing then 
'because the cache has expired 

ExpensiveToGetData = LoadExpensiveDataFromDataSource() 
     Cache("ExpensiveDataKey") = ExpensiveToGetData 
    end If 

    ProcessExpensiveData(ExpensiveToGetData) 

兩個線程都不可能加載緩存,因爲它們都從沒有/過期的緩存請求數據?我在本地機器上運行了一些測試,似乎緩存不止一次被加載。這是一種正常模式?

回答

2

是的,使用該代碼肯定有可能兩個不同的請求將從緩存中得到Nothing,並因此都重新加載數據。如果你想避免這種情況,你需要同步整個獲取數據的操作。

一種方式做同步訪問,將使用類似的代碼:

Dim expensiveToGetData = Cache("ExpensiveDataKey") 

If ExpensiveToGetData is nothing then 
    SyncLock yourLockObject /* YourLockObject should be a Shared object. */ 
     expensiveToGetData = Cache("ExpensiveDataKey") 
     If expensiveToGetData Is Nothing Then 
      ExpensiveToGetData = LoadExpensiveDataFromDataSource() 
      Cache("ExpensiveDataKey") = ExpensiveToGetData 
     End If 
    End SyncLock 
end If 

ProcessExpensiveData(ExpensiveToGetData) 

檢查我們是否得到了獲取鎖之前的數據的想法,是爲了避免在高溫環境中過分抱死加載。如果它不在那裏,我們需要再次檢查鎖內部,因爲另一個線程可能在獲取鎖的同時獲取了數據。

+0

謝謝你,我以爲我瘋了! – Achilles 2010-11-16 21:14:20

+0

在立即達到鎖定以防止競爭條件之前,請考慮冗餘計算緩存值的影響是否與在並行系統中序列化訪問共享資源的成本進行權衡時的影響。 也就是說,當您鎖定此緩存時,從不同線程(不同頁面請求)訪問緩存現在將排隊緩存資源。在網絡環境中,在走下這條路之前,你真的需要認真思考,因爲它會影響你可以並行處理的請求的數量。 – 2013-08-28 23:47:02

2

是的,這是可能的,它不是一個理想的模式。作爲一種快速修復,您可以在緩存上建立互斥鎖作爲快速修復,但理想情況下,更好的設計是將緩存作爲中介加載昂貴的數據本身。這個設計模式比我提到的要多得多,但它應該讓你開始。