发布于 2026-01-06 0 阅读
0

Rails性能分析故事,或者说我是如何发现Faker试图教我的应用程序学习澳大利亚俚语的

Rails性能分析故事,或者说我是如何发现Faker试图教我的应用程序学习澳大利亚俚语的

很久以前(其实是几天前),我一直在做一个小的重构任务:将其集成factory_bot到邮件预览中。

看起来是个很简单的任务:加载factory_bot_rails并包含语法方法:

# spec/mailers/previews/application_preview.rb

require "factory_bot_rails"

class ApplicationPreview < ActionMailer::Preview
  include FactoryBot::Syntax::Methods

  private

  # user record for previews
  def user
    @user ||= build_stubbed :user
  end
end
Enter fullscreen mode Exit fullscreen mode

完成上述操作后,我检查了本地一切是否正常,并发现了一些奇怪的事情:

邮件预览

哇!我们居然有这么多语言版本!在我们这个只有英文版的应用程序里!太棒了!
不,其实不是

我很快找到了它的来源:这是faker我们工厂里使用的宝石。

我查看了代码库,有点惊讶:

require 'i18n'

#...

I18n.load_path += Dir[File.join(mydir, 'locales', '**/*.yml')]
I18n.reload! if I18n.backend.initialized?
Enter fullscreen mode Exit fullscreen mode

Faker 会加载所有语言环境文件,不让你选择想要的语言环境。这让我感到意外。

注意:您可以通过设置来明确指定要在应用程序中使用的区域设置config.i18n.available_locales;如果未设置,则所有已加载的区域设置都将可用。

我决定测试一下加载大量不必要的 YML 文件会对应用程序启动时间产生什么影响。

由于i18n系统会延迟加载语言环境,我已在我的代码中添加了以下行rspec_helper.rb来强制加载:

# add to rails_helper.rb
I18n.backend.load_translations
Enter fullscreen mode Exit fullscreen mode

注意:由于我们faker在工厂中使用,因此几乎每次测试都需要设置区域设置。

我的软件包里已经包含了所需的test-prof组件,所以分析启动时间只需要运行这一条命令:

$ SAMPLE=1 TEST_STACK_PROF=boot TEST_STACK_PROF_FORMAT=json bundle exec rspec
Enter fullscreen mode Exit fullscreen mode

让我解释一下这里发生了什么。

我们“告诉”Test Prof使用Stack Prof启动模式来分析我们的测试运行

在这种模式下,stackprof程序会在加载完成后立即开始收集样本,并在第一次测试运行之前(更准确地说,是在 RSpec before(:suite)hook 中)停止。

我们还传递参数SAMPLE=1,只执行一个随机测试(Test Prof 也提供了此功能):我们不在乎具体的例子,因为我们正在分析启动时间。

最后,TEST_STACK_PROF_FORMAT它用于生成 JSON 格式的分析报告(该功能已添加stackprof自身,但尚未发布)。

如何处理这份 JSON 报告?让我们把它加载到Speedscope中!

Speedscope是一个火焰图查看器,它可以将流行的分析器(包括stackprof)生成的 JSON 报告可视化。

注意:什么是火焰图以及如何解读火焰图?请查看“官方文档”以及Miha Rekar 的演讲

这就是我发现的:

使用默认 faker 的火焰图

Faker 的默认行为(加载所有翻译)

加载语言环境耗时约 1.1 秒。

如果我们只加载英文文件(使用此补丁)会怎样?

带有纤细伪装者的火焰图

已打补丁的 Faker(仅加载英文翻译)

加载语言环境仅用了约 0.4 秒。

看起来没什么大不了的😕

如果我们再加上其他条件,bootsnap就可以在不“修补”的情况下达到同样的效果faker

使用 Bootsnap 绘制火焰图

默认的带 Bootsnap 的 Faker

也许我们浪费了很多内存?

memory_profiler让我们尝试使用gem来测量内存占用:

require "memory_profiler"

MemoryProfiler.report do
  I18n.backend.load_translations
end.yield_self(&:pretty_print)
Enter fullscreen mode Exit fullscreen mode

加载所有可用语言环境时:

retained objects by gem
-----------------------------------
    147586  psych
      5462  i18n-1.5.3
         2  activesupport-6.0.0.beta1

retained objects by class
-----------------------------------
    148628  String
      2550  Array
      1022  Symbol
       848  Hash
         2  Proc
Enter fullscreen mode Exit fullscreen mode

还有仅限英文的版本:

retained objects by gem
-----------------------------------
     44301  psych
      3418  i18n-1.5.3
         2  activesupport-6.0.0.beta1

retained objects by class
-----------------------------------
     45240  String
      1202  Array
       910  Symbol
       367  Hash
         2  Proc
Enter fullscreen mode Exit fullscreen mode

所以,2.6MB 和 7.8MB 之间的差别可以忽略不计。再说一遍。

我们必须承认,就此案而言,我们的分析并未发现任何重大问题。

这也可以算是一个圆满的结局🙂)

PS 还可以看看这些关于使用 Test Prof 进行性能分析的帖子:“Ruby 测试运行缓慢的好医生”“Ruby 测试的工厂疗法”

PPS:是的,Faker确实支持澳大利亚俚语


请访问https://evilmartians.com/chronicles阅读更多开发文章

文章来源:https://dev.to/evilmartians/rails-profiling-story-or-how-i-caught-faker-trying-to-teach-my-app-australian-slang-8ai