我有一个类方法的模型,它在计算中很沉重,我每次请求调用很多次。如何在Rails中记忆一个类方法?
理想情况下,我想缓存一个请求的持续时间的结果。
在这种情况下,最佳实践是什么?
例子:
class MyClass < ActiveRecord::Base
def self.heavy_method; ... ; end
end
然后在助手
def helper
MyClass.heavy_method
end
该辅助许多意见
我有一个类方法的模型,它在计算中很沉重,我每次请求调用很多次。如何在Rails中记忆一个类方法?
理想情况下,我想缓存一个请求的持续时间的结果。
在这种情况下,最佳实践是什么?
例子:
class MyClass < ActiveRecord::Base
def self.heavy_method; ... ; end
end
然后在助手
def helper
MyClass.heavy_method
end
该辅助许多意见
这是一个非常通用的解决方案,可能适合你。
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
注意,在类变量存储的东西可能会导致线程安全问题,因为高速缓存的结果将在线程之间共享。
如果这可能是您的应用程序的问题,您可能需要将数据存储在线程中而不是使用类变量。
很好的回答。不过,更简单的重置会解决所有类实例变量。 'self.instance_variables.each {| v | instance_variable_set(v,nil)}' – steel 2016-04-06 21:07:21
值得注意的是,您可能会使用带有多个线程的Web服务器。同时在不同线程上的两个请求将竞争和争夺缓存。使用此解决方案缓存每个请求是不可取的。 [RequestStore](https://github.com/steveklabnik/request_store)gem是线程安全的 – JustinBull 2017-08-22 16:00:38
使用你能不能只拘泥于结果的变量?对于通用缓存,memcache将是适当的。
为了获得更好,更完整的答案,请提供有关您问题的更多详细信息。
感谢@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
,而不是保持值在内存中。
什么类的类?换句话说,它住在哪里?它是一种类方法(与实例相反)是否合理?它是怎么叫的;它跨多个对象吗? – 2013-04-21 14:59:21