【问题标题】:Rails application config access slow - why?Rails 应用程序配置访问缓慢 - 为什么?
【发布时间】:2013-05-13 05:30:37
【问题描述】:

我们总是将应用程序配置放入环境文件中。这对生产管理没有好处,所以现在我们通过初始化程序加载它:

# myinitializer.rb
ApplicationConfig = YAML.load_file("#{Rails.root}/config/application/default.yml").symbolize_keys()

当我们开始通过ApplicationConfig 访问配置时,应用程序测试性能变得更糟。一个 rspec 套件从 4 秒缩短到 30 秒。

在我们的应用程序控制器中,我们需要使用before_filter 执行一些操作,其工作原理如下:

before_filter :extra_control

def extra_control
  if ApplicationConfig.some_flag
    ...
  end
end

声明一个指向ApplicationConfig的变量可以完全恢复性能:

config = ApplicationConfig

def extra_control
  if config.some_flag
    ...
  end
end

为什么?为什么通过全局变量访问它会破坏性能?我们在视图和其他控制器的整个代码库中执行此操作。我们是否需要以不同的方式执行此操作,例如通过将实例变量注入所有控制器?

编辑:我们确实验证了从 YAML 加载配置的代码被调用一次,因此重复加载似乎不是根本原因。

编辑:事实证明,这是一个设置变量导致的错误,该设置变量被加载为字符串而不是布尔值,导致应用程序进入测试睡眠模式:(抱歉,感谢您的尝试。我生命中的 3 天我永远不会回来!

【问题讨论】:

  • 只有在测试环境下更差吗?您是否检查过在测试环境的哪个阶段调用了初始化程序?您可以通过调试器或添加一些打印来做到这一点。
  • 我没有关于它是否只是在测试中变慢的数据,但我知道初始化器在测试和开发中都被调用一次 - 所以它不是一个重复的初始化器调用减慢它。
  • 另请注意:性能下降仅在直接访问ApplicationConfig时才会出现,将其分配给变量时会消失,如上所示。
  • 嗯,这对我来说无法重现。您是否尝试分析您的测试?也许与它们的实施方式有关?
  • @xcut 拥有 3k 的声誉,您现在应该知道,在 Stack Exchange 网站上,我们希望提问的人接受答案,而不是更改标题以包含“已解决”。如果这意味着您必须编写自己的答案,那很好,但请接受该问题的答案。如果不出意外,它为其他人树立了一个好榜样。

标签: ruby-on-rails app-config


【解决方案1】:

我无法解释您的方法为何缓慢,但也许值得研究另一种处理设置的方式。我更喜欢拥有一个包含配置信息的单例类的想法:

class SiteSettings
    def initialize
        @settings = {}
    end

    @@instance = SiteSettings.new

    def set_setting(key, value)
        @settings ||= {}
        @settings[key] = value
    end

    def self.setting(key, value)
        @@instance.set_setting(key, value)
    end

    def settings
        @settings
    end

    def self.method_missing(meth, *args, &block)
        if @@instance.settings.has_key?(meth)
            @@instance.settings[meth]
        else
            super
        end
    end

    setting :test_setting, 'test'
    setting :another_test_setting '.....'
end

puts SiteSettings.test_setting
puts SiteSettings.another_test_setting

Discourse app 采用了类似的方法。

【讨论】:

  • 感谢您的努力 - 问题最终无关紧要。仅供参考,我们加载一个 YAML 文件,然后在其上 rush Hashie 以生成一个对象,这非常有效,并且不会影响性能。
【解决方案2】:

尝试使用 const:

APPLICATIONCONFIG = YAML.load(File.read(File.expand_path("#{RAILS_ROOT}/config/application/default.yml", __FILE__)))

APPLICATIONCONFIG = YAML::load(File.open("#{RAILS_ROOT}/config/application/default.yml"))

我认为它会使您的文件变慢,因为加载文件但未打开/读取。

【讨论】:

  • 恐怕这对速度没有任何影响。
【解决方案3】:

我认为这将有助于确定 YAML 文件加载\读取是否缓慢,或者 YAML 解析是否缓慢。我的猜测是每次调用 ApplicationConfig 变量时,ruby 都会解析 YAML 文件。您可以尝试将其重命名为APPLICATION_CONFIG,如下所示:

APPLICATION_CONFIG = YAML.load(File.read(Rails.root.join('config', 'application', 'my_config.yml')))

请不要在所有控制器中注入实例变量 :)

【讨论】:

  • 恐怕这对速度没有任何影响。
【解决方案4】:

这里的其他答案没有任何区别 - 这是由一个不相关的问题引起的。记录在案

  • rspec 只调用一次初始化程序
  • 使用 ApplicationConfig 或 APPLICATION_CONFIG 没有区别
  • 分配给变量也没有产生速度差异

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-04
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多