2010-11-16 70 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

是的,这是可能的,它不是一个理想的模式。作为一种快速修复,您可以在缓存上建立互斥锁作为快速修复,但理想情况下,更好的设计是将缓存作为中介加载昂贵的数据本身。这个设计模式比我提到的要多得多,但它应该让你开始。