我的一个rails应用程序是一个拥有大量代码库的rails 2.2应用程序。突然间,开发模式似乎非常慢。这特别是由于
config.cache_classes = false
config/environments/development.rb
中的选项 - 当我将其设置为true时,它会恢复正常。我预计缺乏缓存可以减缓它的速度,但我看到的减速量是荒谬的:有时会在日志中发生任何事情之前等待30秒!一旦我看到日志文件中开始发生的事情,那么页面构建正常进行。我认为这刚刚开始发生,但我不知道我能做些什么来触发它。
有谁知道我如何调查这个问题?我现在要做的就是在日志文件中没有发生任何30秒的时间。
感谢任何指针 - 最多
编辑 - 刚注意到,当我关闭mongrel_rails(用于在开发模式下运行应用程序)时,我收到此消息:Mon Jul 25 16:28:06 +0100 2011: Reaping 5 threads for slow workers because of 'shutdown'
这可能解释了疯狂的减速,但我不知道为什么会有5个线程在运行。
EDIT2 - 这个应用程序运行在红宝石1.8.6 rvm,但切换回系统ruby(也是1.8.6)没有帮助。
EDIT3 - 刚做了一个实验,我的控制台中的reload!
需要28秒。所以这绝对是问题所在。我只是不明白为什么这么长时间。
答案 0 :(得分:1)
我找到了导致它的原因,而且非常令人惊讶。
答案的短篇小说:
我的应用程序的路径已经很长了,这使得在某处使用正则表达式需要很长时间才能测试包含该文件路径的字符串。
答案的长版:
一个疯狂的调试任务*后来我找到了违规行:它在lib/localization.rb
,第56行:
filename =~ /(([a-z]+_?)+)\.yaml$/
它为我运行此行两次,对lang
文件夹中的每个yaml文件运行一次。真正令人担心的是'filename'的值是
"/home/max/work/rails_apps/e_learning_resource_container/e_learning_resource/lang/en.yaml"
和
"/home/max/work/rails_apps/e_learning_resource_container/e_learning_resource/lang/localizations.yaml"
并且,如果我在我的控制台中对此运行正则表达式,我也会在那里遇到大的延迟。所以,问题是针对那些特定字符串测试正则表达式。我只是对正则表达式完成需要多长时间进行了一些实验,你可以看到每个额外的字母在时间上加倍:来自irb(所以与我的应用无关,只是简单的irb)
ruby-1.8.6-p420 :023 > 10.times do |i|
ruby-1.8.6-p420 :024 > string = "#{string1}#{"a"*i}#{string2}"
ruby-1.8.6-p420 :025?> time = Time.now
ruby-1.8.6-p420 :026?> string =~ /(([a-z]+_?)+)\.yaml$/
ruby-1.8.6-p420 :027?> puts "#{string} -> #{Time.now - time}s"
ruby-1.8.6-p420 :028?> end
/home/max/work/rails_apps/e_learning_resource/e_learning_resource_/lang/en.yaml -> 0.133935s
/home/max/work/rails_apps/e_learning_resource/e_learning_resource_a/lang/en.yaml -> 0.149782s
/home/max/work/rails_apps/e_learning_resource/e_learning_resource_aa/lang/en.yaml -> 0.198117s
/home/max/work/rails_apps/e_learning_resource/e_learning_resource_aaa/lang/en.yaml -> 0.316208s
/home/max/work/rails_apps/e_learning_resource/e_learning_resource_aaaa/lang/en.yaml -> 0.501882s
/home/max/work/rails_apps/e_learning_resource/e_learning_resource_aaaaa/lang/en.yaml -> 0.896808s
/home/max/work/rails_apps/e_learning_resource/e_learning_resource_aaaaaa/lang/en.yaml -> 1.707035s
/home/max/work/rails_apps/e_learning_resource/e_learning_resource_aaaaaaa/lang/en.yaml -> 3.322242s
/home/max/work/rails_apps/e_learning_resource/e_learning_resource_aaaaaaaa/lang/en.yaml -> 6.613822s
/home/max/work/rails_apps/e_learning_resource/e_learning_resource_aaaaaaaaa/lang/en.yaml -> 13.399231s
因此,正则表达式开始真正与字符串斗争。如果我改变正则表达式,那么它是
/([a-z]+_?)\.yaml$/
而不是
/(([a-z]+_?)+)\.yaml$/
,即删除内括号周围的(+),然后就可以了:超快。
再加上神秘感,在本地化.rb这个违规的行是没用的!这是包含这一行的整个块:
Dir[RAILS_ROOT + '/lang/*.yaml'].each do |filename|
filename =~ /(([a-z]+_?)+)\.yaml$/
hash = YAML::load(File.read(filename))
file_charset = hash['file_charset'] || 'ascii'
lang = $1
# convert string keys to symbols
symbol_hash = Hash.new
Iconv.open(CONFIG[:web_charset], file_charset) do |i|
hash.each do |key, value|
symbol_hash[key.to_sym] = i.iconv(value)
if key =~ /^active_record_errors_(.*)/
I18n.t("activerecord.errors.messages")[$1.to_sym] =
symbol_hash[key.to_sym]
end
end
end
第2行的正则表达式测试字符串但不对结果做任何事情。即,它不说
if filename =~ etc
...do something
它只是测试它没有明显的原因。所以,我们有一个正则表达式,无论如何都会使用长字符串。双重失败。这可能是这个模块的旧版本,我甚至不知道它是如何进入我们的代码库的。关闭git以对我的固定版本(只是删除该行)发出拉取请求。
*如果有人想知道我的疯狂调试任务是什么,我做了以下操作,在我的应用程序中的每个rb文件的开头和结尾添加调试行。
#get every rb file in the working folder
old_filecount = nil
files = []
fstring = "*/"
count = 0
folder = "./"
while old_filecount != files.size
old_filecount = files.size
files += Dir[File.join(folder,fstring*count, "*.rb")]
count += 1
end
#spam debugging into start and end of every file
files.each do |file|
`sed '1i\\\nputs \"#\{Time.now} - #\{__FILE__}:#\{__LINE__}\"\' #{file} > tmp.txt;mv tmp.txt #{file}`
`echo \";puts \\\"#\{Time.now} - #\{__FILE__}:#\{__LINE__}\\\"\" >> #{file}`
end
hacky呃。