代码之家  ›  专栏  ›  技术社区  ›  Achilles

高并发系统中的缓存访问

  •  3
  • Achilles  · 技术社区  · 14 年前

    假设我有两个线程(Thread1,Thread2),其中线程几乎同时访问给定对象的缓存,如下面的代码所示:

        Dim expensiveToGetData = Cache("ExpensiveDataKey")
    
        If ExpensiveToGetData is nothing then
    'because the cache has expired
    
    ExpensiveToGetData = LoadExpensiveDataFromDataSource()
           Cache("ExpensiveDataKey") = ExpensiveToGetData
        end If
    
        ProcessExpensiveData(ExpensiveToGetData)
    

    这两个线程不可能加载缓存吗,因为它们都从缓存中请求了无内容/过期的数据?我在本地计算机上运行了一些测试,缓存似乎被加载了不止一次。这是正常模式吗?

    2 回复  |  直到 14 年前
        1
  •  3
  •   driis    14 年前

    是的,使用该代码肯定有可能两个不同的请求不会从缓存中获得任何信息,因此这两个请求都会重新加载数据。如果要避免这种情况,需要同步获取数据的整个操作。

    同步访问的一种方法是使用类似于以下内容的代码:

    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)
    

    在获取锁之前检查是否已获取数据的想法,是为了避免在高负载的环境中过度锁定。如果它不在那里,我们需要再次检查锁内部,因为另一个线程可能在我们获取锁时获取了数据。

        2
  •  2
  •   Spencer Hakim    14 年前

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