tl;dr
前回の記事で, JRuby でスクリプトや rspec を実行する際に JVM の起動時間の遅さがすごく気になっていたので, これを短縮する方法について調べたら Nailgun というオプションを使うと良さそうということで試したメモ.
本記事で試す環境は, 前回の記事と同様に以下のような環境を利用する.
$ java -version openjdk version "1.8.0_171" OpenJDK Runtime Environment (build 1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11) OpenJDK 64-Bit Server VM (build 25.171-b11, mixed mode) $ jruby --version jruby 9.2.0.0 (2.5.0) 2018-05-24 81156a8 OpenJDK 64-Bit Server VM 25.171-b11 on 1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11 +jit [linux-x86_64]
Nailgun とは
上記のドキュメントより引用.
In JRuby 1.3, we officially shipped support for Nailgun. Nailgun is a small library and client-side tool that reuses a single JVM for multiple invocations. With Nailgun, small JRuby command-line invocations can be orders of magnitude faster.
Nailgun を利用するには, JRuby を --ng-server
オプションで起動しておいて, 別の端末の JRuby を --ng
オプションを付けて起動する.
# Nailgun サーバーを起動 $ jruby --ng-server & # 別の端末で Nailgun モードでスクリプトを実行 $ jruby -S --ng sample.rb
試す
Hello World
以下のようなコードを用した.
p 'hello world'
これを hello_world.rb として保存して, Nailgun を利用した場合と利用しない場合で実行時間の変化を確認.
# Nailgun を使わない x 3 回 $ time jruby -S hello_world.rb "hello world" real 0m2.414s user 0m6.140s sys 0m0.168s $ time jruby -S hello_world.rb "hello world" real 0m2.524s user 0m6.624s sys 0m0.184s $ time jruby -S hello_world.rb "hello world" real 0m2.441s user 0m6.268s sys 0m0.152s # Nailgun を使う x 3 回 $ time jruby -S --ng hello_world.rb real 0m3.921s user 0m0.032s sys 0m0.016s $ time jruby -S --ng hello_world.rb real 0m0.851s user 0m0.016s sys 0m0.012s $ time jruby -S --ng hello_world.rb real 0m0.763s user 0m0.016s sys 0m0.028s
Nailgun を使わない場合, たかだか Hello world で 3 秒くらい掛かってしまう. Nailgun を利用すると, 初回は Nailgun を利用しない場合と殆ど変わらないが, 2 回目以降は 3 分の 1 程の時間で処理が完了している. 尚, Nailgun を利用した場合, Hello world
が出力されていないが, これは Nailgun サーバーを起動した端末側で出力されている.
minitest
以下のような, 超簡単なテストコードを実行させてみる.
require 'minitest/autorun' class FooTest < Minitest::Test def test_foo assert_equal 'foo', 'foo' end end
これを minitest.rb として保存し, Nailgun を利用した場合と利用しない場合で実行時間の変化を確認.
# Nailgun を使わない x 3 回 $ time jruby -S minitest.rb Run options: --seed 58096 # Running: . Finished in 0.026389s, 37.8950 runs/s, 37.8950 assertions/s. 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips real 0m3.359s user 0m9.492s sys 0m0.196s $ time jruby -S minitest.rb Run options: --seed 9728 # Running: . Finished in 0.032048s, 31.2030 runs/s, 31.2030 assertions/s. 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips real 0m3.523s user 0m10.096s sys 0m0.220s $ time jruby -S minitest.rb Run options: --seed 24004 # Running: . Finished in 0.033907s, 29.4925 runs/s, 29.4925 assertions/s. 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips real 0m3.368s user 0m9.760s sys 0m0.208s # Nailgun を使う x 3 回 $ time jruby -S --ng minitest.rb real 0m1.699s user 0m0.020s sys 0m0.020s $ time jruby -S --ng minitest.rb real 0m1.430s user 0m0.024s sys 0m0.016s $ time jruby -S --ng minitest.rb real 0m1.113s user 0m0.028s sys 0m0.020s
RSpec
以下のような RSpec で実行可能なテストコードを書いてみた.
require 'rspec/expectations' RSpec::Matchers.define :have_word do |expected| match do |actual| actual.include?(expected) end end RSpec.describe 'foo-bar-bar' do it { should have_word('foo') } end
これを rspec.rb として保存し, 動作確認してみる.
# Nailgun を使わない x 3 回 $ time jruby -S rspec rspec.rb ... 略 ... real 0m5.050s user 0m14.120s sys 0m0.248s $ time jruby -S rspec rspec.rb ... 略 ... real 0m4.853s user 0m13.624s sys 0m0.284s $ time jruby -S rspec rspec.rb ... 略 ... real 0m5.101s user 0m14.404s sys 0m0.240s # Nailgun を使う x 3 回 $ time jruby -S --ng rspec rspec.rb real 0m1.510s user 0m0.012s sys 0m0.020s $ time jruby -S --ng rspec rspec.rb real 0m1.795s user 0m0.012s sys 0m0.004s $ time jruby -S --ng rspec rspec.rb real 0m2.585s user 0m0.036s sys 0m0.020s
ぱっと見た感じだと, 何れの場合にも Nailgun を利用した方が圧倒的に処理時間は速いように見える.
以上
すごくイイこと尽くめに感じる Nailgun だが, ドキュメントには以下のように書かれている.
Nailgun seems like a magic bullet, but unfortunately it does little to help certain common cases like booting RubyGems or starting up Rails (such as when running tests). It also can't help cases where you are causing lots of sub-rubies to be launched, and if you have long-running commands the usual Control-C may not be able to shut them down on the server. Your best bet is to give it a try and let us know if it helps.
Nailgun は魔法の弾丸じゃないし, gem の起動やテストの実行時など, Railsの起動などの一般的なケースはほとんど役に立たないとあるので, 実際に利用する場合には注意が必要.
参考
ありがとうございました.