2013-04-21 39 views
9

我有一個類方法的模型,它在計算中很沉重,我每次請求調用很多次。如何在Rails中記憶一個類方法?

理想情況下,我想緩存一個請求的持續時間的結果。

在這種情況下,最佳實踐是什麼?

例子:

class MyClass < ActiveRecord::Base 
    def self.heavy_method; ... ; end 
end 

然後在助手

def helper 
    MyClass.heavy_method 
end 

該輔助許多意見

+0

什麼類的類?換句話說,它住在哪裏?它是一種類方法(與實例相反)是否合理?它是怎麼叫的;它跨多個對象嗎? – 2013-04-21 14:59:21

回答

11

這是一個非常通用的解決方案,可能適合你。

class Klass 
    def self.memoized_expensive_method 
    @memoized_expensive_method_result ||= expensive_method 
    end 

    def self.expensive_method 
    # ... 
    end 
end 

然後,如果您想確保您的代碼在每次請求時都被重新執行,您可以在控制器中使用過濾器。

class Klass 
    def self.reset_expensive_method_cache! 
    @memoized_expensive_method_result = nil 
    end 
end 

class ApplicationController 
    before_filter :reset_klass_expensive_method_cache 

    def reset_klass_expensive_method_cache 
    Klass.reset_expensive_method_cache! 
    end 
end 

注意,在類變量存儲的東西可能會導致線程安全問題,因爲高速緩存的結果將在線程之間共享。

如果這可能是您的應用程序的問題,您可能需要將數據存儲在線程中而不是使用類變量。

+0

很好的回答。不過,更簡單的重置會解決所有類實例變量。 'self.instance_variables.each {| v | instance_variable_set(v,nil)}' – steel 2016-04-06 21:07:21

+0

值得注意的是,您可能會使用帶有多個線程的Web服務器。同時在不同線程上的兩個請求將競爭和爭奪緩存。使用此解決方案緩存每個請求是不可取的。 [RequestStore](https://github.com/steveklabnik/request_store)gem是線程安全的 – JustinBull 2017-08-22 16:00:38

1

使用你能不能只拘泥於結果的變量?對於通用緩存,memcache將是適當的。

爲了獲得更好,更完整的答案,請提供有關您問題的更多詳細信息。

2

感謝@unixcharles,這裏是我最終做

class SomeClass 
    @lock = Mutex.new 

    after_save :clear_cached_calculation 

    class << self 
    def some_calculation 
     @lock.synchronize do 
     @calc ||= heavy_operation 
     end 
    end 

    def clear_calculation 
     @lock.synchronize do 
     @calc = nil 
     end 
    end 

    end 

private 

    def clear_cached_caculation 
    SomeClass.clear_calculation 
    end 
end 

編輯:

這可能是一個更好的解決方案使用Rails.cache.fetch,而不是保持值在內存中。