どちらが最速ですか? ERB vs. HAML vs. Slim
この記事では、最も人気のある3つのRubyテンプレートエンジンであるERB(デフォルトのエンジン)、HAML、SLIMのパフォーマンスをテストおよび分析します。
ベンチマークとは、ビジネスプロセスとパフォーマンスメトリックを業界のベストプラクティスや他社のベストプラクティスと比較することです。一方、負荷テストは、システムに需要を与え、その応答を測定するプロセスです。
私たちの目標は、Rubyコードの実行に使用された時間を測定および報告するためのメソッドを提供するRubyベンチマークモジュールを少し調べることです。いくつかのインラインテンプレートを作成し、それらをテストに対して実行し、3つの異なるエンジンのメトリックを抽出します。
その後、実際のテンプレートビューを作成して負荷テストを行い、それらをサーバーに公開してから、heyツールを使用して負荷テストを実行します。特定のWebアプリケーションに負荷を送信し、各エンドポイント、つまり各テンプレートエンジンのパフォーマンスに関連する完全なデータを取得するための優れた機能を提供します。
もちろん、最初に行うことは、Rubyがすでにインストールされていることを確認することです。この記事の執筆時点では、最新バージョンの2.7.0を使用しています。 Railsgemもインストールしてください。
RubyとRailsの宝石は、私たちが始めるために必要なものです。このチュートリアルでは、Visual Studio Codeがコーディング用のIDEですが、必要に応じて別のコードを選択してください。
次に、Railsプロジェクトのフォルダーを選択し、次のコマンドを実行します。
rails new haml-slim-erb
これにより、必要なすべての依存関係がダウンロードされ、スキャフォールドRailsプロジェクトが作成されます。さあ、探索してください。
コードに進む前に、SLIMとHAMLの依存関係をGemfileに追加する必要があります。 :
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platform: :mri
gem 'haml'
gem 'slim'
end
SQLiteバージョンに関連するプロジェクトにはデフォルトで発生するバグもあります。 Gemfileで見つけます 次のように変更します:
gem 'sqlite3', '~> 1.3.0'
次に、 bundle install
を実行します 依存関係をダウンロードするコマンド。
記事のこの部分では、テストを直接使用します。 フォルダ。それを開くと、いくつかの空のフォルダが表示されます。 ベンチマークという新しいベンチマークを作成しましょう および他の3つのファイル: example_1_test.rb 、 example_2_test.rb 、およびexample_3_test.rb。 。
Rubyはtestで終わる必要があります テストファイルと見なされます。
次に、次のコンテンツを最初のファイルに追加します。
require 'benchmark'
number = (0..50).to_a.sort{ rand() - 0.5 }[0..10000]
puts Benchmark.measure {
20_000.times do
number[rand()] * (0..50).to_a.sort{ rand() - 0.5 }[0..10000][rand()]
end
}
最初の行は、必要なベンチマークモジュールをインポートすることに注意してください。次に、サイズが10.000の0から50までの数値のランダム配列を生成します。これらの大きな数は、処理に少し時間がかかるだけです。
メソッドmeasure
Rubyコードのどこにでも配置して、処理にかかる時間を測定できるため、非常に便利です。今回はputs
によって返され印刷されます 。
内部では、ランダムに生成された同じ配列の実行を20k回ループして、それぞれの値を1つ乗算しています。
このテストファイルを具体的に実行するには、次のコマンドを発行します。
rake test TEST=test/benchmark/example_1_test.rb
結果は次のようになります:
0.702647 0.012353 0.715000 ( 0.721910)
このレポートは、ユーザーのCPU時間、システムのCPU時間、ユーザーとシステムのCPU時間の合計、および経過したリアルタイムをそれぞれ出力します。時間の単位は秒です。
実際には、他のベンチマーク手法をさらに活用します。
Rubyのベンチマークモジュールがどのように機能するかについてもう少し理解できたので、3つのテンプレートに対するいくつかのテストの実行について詳しく説明します。
このために、単一のテンプレートを作成し、それを3つのエンジン構文に変換して、最後にベンチマークメソッドで実行します。
2番目のテストファイルに以下を追加します。
require 'erb'
require 'haml'
require 'slim'
require 'benchmark'
require 'ostruct'
notes = OpenStruct.new title: 'Write an essay', description: 'My essay is about...', randomList: (0..50).to_a.sort{ rand() - 0.5 }[0..10000]
erb_example = <<-ERB_EXAMPLE
<span><%= notes.title %></span>
<span><%= notes.description %></span>
<table>
<tr>
<% notes.randomList.each do |note| %>
<td><%= note %></td>
<% end %>
</tr>
</table>
ERB_EXAMPLE
slim_example = <<-SLIM_EXAMPLE
span= notes.title
span= notes.description
table
tr
- notes.randomList.each do |note|
td= note
SLIM_EXAMPLE
haml_example = <<-HAML_EXAMPLE
%span= notes.title
%span= notes.description
%table
%tr
- notes.randomList.each do |note|
%td= note
HAML_EXAMPLE
context = OpenStruct.new notes: notes
__result = ''
Benchmark.bmbm(20) do |bcmk|
bcmk.report("erb_test") { (1..2000).each { ERB.new(erb_example, 0, '-', '__result').result binding } }
bcmk.report("slim_test") { (1..2000).each{ __result = Slim::Template.new { slim_example }.render(context) } }
bcmk.report("haml_test") { (1..2000).each { __result = Haml::Engine.new(haml_example).render(binding) } }
end
まず、必要なモジュールをインポートします。テンプレートエンジンの他に、 ostruct
もインポートしています モジュール。 OpenStruct
Hash
に似た、メタプログラミングのデータ構造です。 、これにより、任意の属性とそれに付随する値を定義できます。
値を格納するためにクラス構造全体を作成する必要がないため、これは便利です。インラインで定義できます。
私たちの構造体は基本的にNote
タイトル、説明、および乱数のリストを含むオブジェクト。これにより、処理時間が長くなります。
各テンプレートエンジンがどのように機能するかに焦点を当てません。これについては、彼らの公式ドキュメントを参照できます。ただし、それらの構文は非常に簡単に理解できます。
魔法はコードの最後に配置されます。現在、 bmbm
を使用しています 最初の方法よりも少し多くのことを行う方法。ガベージコレクションやメモリリークなどの外部要因により、ベンチマーク結果が歪む場合があります。この方法では、テストを2回実行することで、この影響を最小限に抑えようとします。本当の時間。これについて詳しくは、こちらをご覧ください。
最後に、 bmbm
のそれぞれ の内部コード行は、各テンプレートの作成中に2000回ループを実行します。焦点は、テンプレートの割り当てとレンダリングにあります。
このテストファイルを実行した後の結果は次のとおりです。
Rehearsal --------------------------------------------------------
erb_test 0.311534 0.002963 0.314497 ( 0.314655)
slim_test 2.544711 0.004520 2.549231 ( 2.550307)
haml_test 1.449813 0.003169 1.452982 ( 1.454118)
----------------------------------------------- total: 4.316710sec
user system total real
erb_test 0.298730 0.000679 0.299409 ( 0.299631)
slim_test 2.550665 0.004148 2.554813 ( 2.556023)
haml_test 1.432653 0.001984 1.434637 ( 1.435417)
2つの結果ブロックは、リハーサルから実際のものを吸収するために分離されています。
最後のテスト結果では、ERBが最良のオプションであり、SLIMが最悪であると想定できます。繰り返しますが、状況によって異なります。
そのテストでは、ループするたびに、新しいをインスタンス化する必要があります。 テンプレートエンジンオブジェクト。これは最適なフローではありません。
次のコードスニペットに示すように、少し変更して、このインスタンス化を外側に移動しましょう。
erb_engine = ERB.new(erb_example, 0, '-', '__result')
slim_engine = Slim::Template.new { slim_example }
haml_engine = Haml::Engine.new(haml_example)
Benchmark.bmbm(10) do |bcmk|
bcmk.report("erb_test") { (1..2000).each { erb_engine.result binding } }
bcmk.report("slim_test") { (1..2000).each{ __result = slim_engine.render(context) } }
bcmk.report("haml_test") { (1..2000).each { __result = haml_engine.render(binding) } }
end
コードは以前とまったく同じです。ここで、テストを再度実行すると、結果として次のようなものが表示されます。
Rehearsal ----------------------------------------------
erb_test 0.127599 0.002407 0.130006 ( 0.130137)
slim_test 0.046972 0.000841 0.047813 ( 0.047858)
haml_test 0.208308 0.002239 0.210547 ( 0.210769)
------------------------------------- total: 0.388366sec
user system total real
erb_test 0.118002 0.000556 0.118558 ( 0.118618)
slim_test 0.040129 0.000090 0.040219 ( 0.040320)
haml_test 0.205331 0.001163 0.206494 ( 0.206680)
どちらが現在最高で最悪であるかに注意してください。これは、完璧なエンジンという点で特効薬がないことを示すためだけのものです。
コーディングのスタイルに適した機能をテストおよび分析する必要があります。さらに、Ruby Profilerなどの他の補助ツールがあり、コードがこのように動作する方法と理由をよりよく理解するために使用できます。
私たちの現実に近いものに移りましょう。いくつかのメモをリストした実際のテンプレートのベンチマークを行います(テンプレートエンジンごとに3つ、1つ)。
ベンチマーク
以降 モジュールはRailsコードで行われるため、テンプレートエンジンの内部プロセスに関連するいくつかの重要な手段が失われます。
このタイプのベンチマークテストでは、プロセスの最初から要求の到着から、応答データがビューに到達するまでのビジネスロジック処理まで、各エンジンが全体としてどのように機能するかを確認できます。この最後のステップには、具体的には、負荷テストで測定できる解析およびレンダリングプロセスや、ベンチマーク
などの一連のステップが含まれます。 できません。
まず、例ごとにRailsコントローラーを作成しましょう。
rails g controller notes_erb index
rails g controller notes_haml index
rails g controller notes_slim index
このコマンドは、慣れ親しんだ一般的なRailsファイルの束を自動生成します。
次に、 notes_erb_controller.rbを開きます。 ファイルを作成し、その内容を次のように変更します:
class NotesErbController < ApplicationController
def index
@notes = JSON.parse(Constants::NOTES, object_class: OpenStruct)
end
end
ここで、テンプレートにデータをフィードします。エンジンごとに1つのコントローラークラスがあることに注意してください。
基本的に、インライン定数からJSONを取得しています。応答は新しいOpenStruct
に解析されます オブジェクトとエンジンに返されます。
注意事項コード> 定数は、 constants.rbという新しいファイルに配置する必要があります 。先に進んで作成し、次のコンテンツを追加します。
class Constants
NOTES = '[
{
"title": "Walk the dog",
"description": "Bla bla",
"tasks": [{
"title": "Task #1"
},
{
"title": "Task #2"
},
{
"title": "Task #3"
}]
},
...
{
"title": "Walk the dog",
"description": "Bla bla",
"tasks": [{
"title": "Task #1"
},
{
"title": "Task #2"
},
{
"title": "Task #3"
}]
}
]
'
end
より多くの音符要素の省略記号を変更してください。さらに、他の各コントローラーでロジックを複製することを忘れないでください。
ERBビューの作成
次に、例のビューを作成します。これを行うには、 views / notes_erb
に移動します フォルダを作成し、他の2つのファイルを作成します: note.html.erb
およびtask.html.erb
。ビュー、パーシャル、レイアウトを含む例を作成するのに役立ちます。
このようにして、私たちの例がRailsエンジンを最も探索したことを保証します。必ず両方のviews/ notes_haml
と同等のファイルを作成してください およびviews/ notes_slim
。
index.html.erb
から始めましょう コード:
<style>
h2 {
text-align: center;
}
table, td, th {
border: 1px solid #ddd;
text-align: left;
}
table {
border-collapse: collapse;
width: 80%;
margin: auto;
}
th, td {
padding: 15px;
}
</style>
<h2>List of Notes</h2>
<table>
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Tasks</th>
</tr>
</thead>
<tbody>
<%= render partial: 'notes_erb/note', collection: @notes %>
</tbody>
</table>
ここには特別なことは何もありません。部分的な_note.html.erb
をインポートしていることに注意してください ファイル、およびコレクション
を渡す パラメータ: @notes
以前にコントローラーで作成されました。
ちなみに、メモの内容は次のとおりです。
<tr>
<td>
<span><%= note.title %></span>
</td>
<td>
<span><%= note.description %></span>
</td>
<td>
<ul>
<%= render partial: 'notes_erb/task', collection: note.tasks %>
</ul>
</td>
</tr>
タスク
にアクセスするもう1つの部分があります 今回は配列します。
_task.html.erb
のコンテンツ 次のとおりです:
<li><%= task.title %></li>
HAMLの見解
あるエンジンから別のエンジンへの構文が非常に似ていることに気付くでしょう。変化するのは、それぞれの冗長性だけです。たとえば、SLIMはその中で最もクリーンなものです。
3つのファイルのコードを見てください:
# Content of index.html.haml
:css
h2 {
text-align: center;
}
table, td, th {
border: 1px solid #ddd;
text-align: left;
}
table {
border-collapse: collapse;
width: 80%;
margin: auto;
}
th, td {
padding: 15px;
}
%h2 List of Notes
%table
%thead
%tr
%th Title
%th Description
%th Tasks
%tbody
= render partial: 'notes_haml/note', collection: @notes
# Content of _note.html.haml
%tr
%td
%span= note.title
%td
%span= note.description
%td
%ul
= render partial: 'notes_haml/task', collection: note.tasks
# Content of _task.html.haml
%li= task.title
非常に似ていますね
SLIMの見解
最後に、SLIMの見解があります。これが他の2つとの最大の違いです。全体の構造がより明確になります:
# index.html.slim
css:
h2 {
text-align: center;
}
table, td, th {
border: 1px solid #ddd;
text-align: left;
}
table {
border-collapse: collapse;
width: 80%;
margin: auto;
}
th, td {
padding: 15px;
}
h2 List of Notes
table
thead
tr
th Title
th Description
th Tasks
tbody
= render partial: 'notes_haml/note', collection: @notes
# _note.html.slim
tr
td
span= note.title
td
span= note.description
td
ul
= render partial: 'notes_haml/task', collection: note.tasks
# _task.html.slim
li= task.title
また、レイアウトをそれぞれのエンジン構文に変換する必要があります。 ビュー/レイアウトの下に2つの新しいファイルを作成する必要があります フォルダ: application.html.haml およびapplication.html.slim 。
その仕事は宿題としてあなたに任せます。ただし、難しい場合は、記事の最後にあるGitHubプロジェクトのリンクで私のバージョンを参照できます。
最後に、例をテストします。まず、 rails
を実行してアプリケーションを起動します 指図。 http:// localhost:3000/アドレスから始まります。
ビューは次のようになります:
各テンプレートエンジンの例は、 config / routers.rbで自動生成されたそれぞれのURLで利用できます。 ファイル。
これらの例をベンチマークテストするために、heyベンチマークツールを使用します。これは非常に単純で、ベンチマーク分析に役立つ情報を提供します。コマンドは次のとおりです。
$ hey https://localhost:3000/notes_erb/index
Summary:
Total: 9.3978 secs
Slowest: 9.1718 secs
Fastest: 0.0361 secs
Average: 1.2714 secs
Requests/sec: 21.2816
$ hey https://localhost:3000/notes_haml/index
Summary:
Total: 10.8661 secs
Slowest: 10.2354 secs
Fastest: 0.1871 secs
Average: 1.4735 secs
Requests/sec: 18.4058
$ hey https://localhost:3000/notes_slim/index
Summary:
Total: 11.3384 secs
Slowest: 10.7570 secs
Fastest: 0.0437 secs
Average: 1.5406 secs
Requests/sec: 17.6392
ご覧のとおり、すべてのエンジンは実行時間の点で非常に近いです。実行するリクエストのデフォルト数は200ですが、この値は -n
を使用して変更できます。 オプション。
1200リクエストで実行された同じテストを見てみましょう:
$ hey -n 1200 https://localhost:3000/notes_erb/index
Summary:
Total: 52.2586 secs
Slowest: 19.2837 secs
Fastest: 0.0389 secs
Average: 0.6960 secs
Requests/sec: 22.9627
$ hey -n 1200 https://localhost:3000/notes_haml/index
Summary:
Total: 61.7637 secs
Slowest: 18.5290 secs
Fastest: 0.0442 secs
Average: 0.8557 secs
Requests/sec: 19.4289
$ hey -n 1200 https://localhost:3000/notes_slim/index
Summary:
Total: 63.1625 secs
Slowest: 19.9744 secs
Fastest: 0.0874 secs
Average: 0.7959 secs
Requests/sec: 18.9986
同時リクエストの数を増やすと、合計処理時間と平均処理時間の差が大きくなります。明らかに、何千もの並列リクエストを伴うこのシナリオは非常に具体的であり、あまり一般的ではありません。ただし、負荷テストはそれがすべてであり、エンドポイントを限界まで引き上げます。
heyツールは、応答時間ヒストグラムなどの他の情報も出力します。
これは、各リクエストが完了するまでにかかった平均時間を概算で示しています。この例では、ほとんどのリクエスト(1048)が1.893秒で完了したことは明らかです。これが、ストレステストを同時に実行することが望ましい理由です。
レイテンシの分散、DNSダイヤルアップとルックアップの詳細、リクエストの書き込み、待機時間と読み取り時間、エラーなどに関する詳細情報もあります。
その他のカスタムオプション/結果については、ドキュメントを確認してください。
この例のソースコードはここにあります。
この種のテストは、プロジェクトのニーズにより適したテンプレートエンジンを定義するのに役立ちます。これまで見てきたように、一部の小さなコードスニペットは実行の全体的なパフォーマンスを突然変更する可能性があるため、実装が不十分なコードには注意してください。
もう1つの興味深い点は、ERBは、デフォルトのRailsエンジンとして、その仕事にも優れているということです。一部のテストでは他のエンジンが高速であることに加えて、ERBは常にその価値を証明するのに十分な距離にあります。
最後に、キャッシュ、プロキシ、データベースの使用、その他の保存メカニズム、キューなどの非同期ツールなど、テストのその他の重要な要素を宿題として検討することをお勧めします。これらのアイテムは、ビューの動作やレンダリングにかかる処理時間において常に重要な役割を果たします。頑張ってください!
-
お住まいの地域で最も速いVPNはどれですか?この無料ツールはあなたに教えてくれます
VPNがファイル共有などの違法行為にのみ必要であると思われる場合は、もう一度考えてみてください。真実は、VPNを使用して自分自身を保護したり、粗雑なネットワークパフォーマンスを改善したりする必要がある場合が多いということです。 たとえば、VPNを使用すると、一時的に海外にいるときに米国のNetflixにアクセスできます。 VPNに対する最近のNetflixの取り締まりは、多くのコードカッターに打撃を与えましたが、他にも用途があります。検索プライバシー、国際VoIP、さらには公共Wi-Fiの保護です。 ただし、すべてのVPNが同じように作成されるわけではありません。私にとってうまくいくもの
-
どのRubyIDEを使用する必要がありますか?
エディター内で開発者として多くの時間を費やすことになるため、快適で生産性の高いエディターを使用することが重要です。 この記事の内容: どのRubyIDE/エディターがあなたに適しているかを選択するお手伝いをしたいと思います ! この決定について強調する必要はありません。1つ選んで、数週間試してみて、どのように感じるかを確認してください。エディターは後でいつでも変更できます。 探すべきことがいくつかあります : 作業を簡単にするために利用できるRuby関連のプラグイン エディターがオープンソースであるかどうか 生産性を向上させる組み込み機能(コードスニペット、オートコンプリート、邪魔に