Rails应用程序配置访问缓慢 - 为什么?

7

我们过去常常将应用程序配置放在环境文件中。但这样做对于生产管理来说并不好,所以现在我们通过一个初始化器来加载它:

# 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天!

我没有数据表明它只是在测试中变慢,但我知道初始化程序在测试和开发中都只被调用一次 - 因此不是重复的初始化程序调用导致它变慢。 - xcut
嗯,这个问题我这边无法重现。你尝试过对测试进行分析吗?也许是实现方式有关? - Anton Roslov
你的配置文件有多大? - Harish Shetty
配置文件大约有20个条目。我还确认它仅被读取一次。但是,与上面所示的赋值给变量然后读取相比,引用ApplicationConfig仍然较慢。 - xcut
2
@xcut,以你3000声望的经验,你应该知道在 Stack Exchange 网站上我们希望提问者接受答案,而不是修改标题并包含“已解决”。如果这意味着你必须自己编写答案,那也没关系,但请接受一个问题的答案。至少,这为其他人树立了一个好榜样。 - Old Pro
显示剩余3条评论
4个回答

0
我不知道你的方法为什么慢,但也许值得考虑另一种处理设置的方式。我更喜欢使用包含配置信息的单例类的想法:
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 应用程序 采用类似的方法。


1
感谢您的努力 - 最终问题与此无关。顺便说一下,我们加载一个YAML文件,然后使用Hashie快速生成对象,这非常有效,没有性能损失。 - xcut

0

我认为弄清楚 YAML 文件加载 / 读取慢还是 YAML 解析慢会有所帮助。 我猜想 Ruby 每次调用 ApplicationConfig 变量时都在解析 YAML 文件。 你能否尝试将其重命名为 APPLICATION_CONFIG,像这样:

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

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

很抱歉,这并没有产生任何速度上的差异。 - xcut

0
尝试使用const: < p > APPLICATIONCONFIG = YAML.load(File.read(File.expand_path(“#{RAILS_ROOT} /config/application/default.yml”,__ FILE__)))

< p >或

< p > APPLICATIONCONFIG = YAML :: load(File.open(“#{RAILS_ROOT} /config/application/default.yml”))

< p >我认为它会使您的文件变慢,因为它会加载文件而不是打开/读取。


很抱歉,这并没有带来任何速度上的差异。 - xcut

0

这里的其他答案没有起到作用 - 这是由一个无关的问题引起的。记录一下

  • 初始化程序由rspec精确调用一次
  • 使用ApplicationConfig或APPLICATION_CONFIG没有区别
  • 将值分配给变量也不会产生速度差异

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接