在Ruby on Rails中,如何在会话之间将对象保留在内存中

时间:2010-07-28 14:58:08

标签: ruby-on-rails memory object persistence

我正在尝试构建一些东西(最终是一个宝石,但现在是一个应用程序),其工作原理如下。

假设例如DB记录是狗的品种。每个品种都有一个Dog父类和一个子类。直到运行时才知道实际的品种。

当服务器开始时,它将从DB加载记录并基于记录实例化类的实例,例如我可能有两只小猎犬和狮子狗。当有人来到服务器时,他们可能想要访问其中一个狗实例。

为什么不动态创建实例?在我的例子中,“狗”基本上是包含算法和数据的类。算法不会改变,数据变化很少(按天数排序),但算法本身的执行(使用数据和传递的一些动态数据,如时间戳)将每秒多次访问。

重新创建对象的实例并每次只加载数据只是为了在下一个请求中再次执行它(请求不会更改对象的状态),这将是愚蠢的。当我可以重复使用同一个对象时,我会创建并销毁多个对象。

将它保留在会话中是没有意义的,因为想要一只贵宾犬的人不需要在她的会话对象中有beagles信息;这是无关紧要的(并且没有扩展)。

如何将这些对象保留在内存中?我基本上想要一个查找表来保存实例。在Java中,我将创建一个包含某种类型的hashmap或数组的单例,它们位于内存中。在rails中我通过在lib文件夹中创建一个单例类来尝试这个。我想 - 我可能不理解这一点 - 当会话消失时,实例(事实上它是单身人士没有实际意义)正在丢失。

我找到的最接近的答案是http://www.ruby-forum.com/topic/129372,它基本上将所有内容放在课程领域和方法中。不知何故,这似乎不对。

TIA!

另外:我来自Java。在Java中,我只是创建一个位于堆上或可能位于JNDI树中的对象,当HTTP请求进入时,它们将由一个servlet或EJB或一些每个请求项处理,然后可以访问持久对象。我似乎无法在rails中找到相应的东西。

5 个答案:

答案 0 :(得分:10)

也许你的例子很简单。我假设您的对象非常复杂,并且您的基准测试显示构建它们对于每个请求都是不合理的。

在生产模式下,不会在请求之间卸载类,但是这些类的实例是。因此,使用班级的班级成员听起来像是找我的方式。只需使用它来存储您的实例。

class ObjectCache
  @@objects = {:beagle => Beagle.new, :poodle => Poodle.new}

  def lookup key
    @@objects[key.to_sym]
  end
end

答案 1 :(得分:6)

我不会过分担心加载和丢弃对象,除非你能提出一个证明它是一个问题的基准。当然,每个请求都会创建大量的中间对象,这些对象通常会在几毫秒内创建和销毁。

通常最好只关注仅加载所需内容,对数据库进行反规范化以将频繁访问的数据或方法推送到方便的位置,或者将复杂计算的结果保存在缓存字段中。

首先进行基准测试,仅在需要时进行优化。

将模型实例保存到类高​​速缓存可以起作用,但它只是生产环境中的一个选项,其中模型类不会随每个请求重新加载。它还会使您暴露于由陈旧数据引起的错误。

如果您遇到无法使用这些方法解决的扩展问题,您可能需要使用Rack和EventMachine的组合来研究为部分功能构建持久性服务器。有许多方法可以构建可以使用预先加载的数据集执行复杂计算的后台进程,但具体方法取决于几个因素,例如您正在使用的数据类型以及频率它将被访问。

答案 2 :(得分:0)

在生产中,控制器和模型类不会在请求之间重新加载,因此您有几个选项:

  • 在application_controller
  • 中将对象设置为类变量
  • 在模型类本身中创建返回值
  • 的单例方法

答案 3 :(得分:0)

是的,也可以防止类在开发模式下卸载。这不仅仅是生产模式的事情。虽然默认情况下会在生产模式下发生,但您必须在开发模式下手动设置它。

答案 4 :(得分:0)

为了不在每个请求上重新加载您的类,即使在开发模式下,您也可以将它们移动到自动加载路径之外的某个位置(如果使用app和lib目录之外的默认值)。这样,您可以在请求之间保留这些对象类,从而使用它们来存储对每个请求都相同的数据。