将来を見据えたウェブ・アプリケーションの構築:The Codestのエキスパート・チームによる洞察
The Codestが、最先端技術を駆使してスケーラブルでインタラクティブなウェブアプリケーションを作成し、あらゆるプラットフォームでシームレスなユーザー体験を提供することにどのように秀でているかをご覧ください。The Codestの専門知識がどのようにデジタルトランスフォーメーションとビジネス...
多くの利点があるにもかかわらず、Ruby on Railsはまだ比較的遅いウェブフレームワークだと考えられている。TwitterがRailsからScalaに移行したことは周知の通りです。しかし、いくつかの巧妙な改良を加えることで、アプリを大幅に高速化することができます!
ルビー は重厚なオブジェクト指向言語である。実際 ルビー はオブジェクトである。不必要なオブジェクトを作成すると、プログラムに多くのメモリ使用量を追加することになるかもしれないので、避ける必要がある。
その違いを測定するために メモリプロファイラ ジェムと、タイム・パフォーマンスを測定するための内蔵ベンチマーク・モジュール。
require "memory_profiler"
report = MemoryProfiler.report do
データ = "X" * 1024 * 1024 * 100
data = data.downcase
終了
report.pretty_print
以下のリストでは、100MBの文字列を作成し、そこに含まれる各文字をダウンケースしている。ベンチマークの結果は以下の通りである:
割り当てられた合計210765044 バイト (6 オブジェクト)
しかし、6行目をこう置き換えてみよう:
data.downcase!
おそらく、200万レコードの巨大なデータコレクションをcsvファイルからフェッチする必要がある。一般的には、次のようになる:
require 'benchmark'
ベンチマーク.bm do |x|
x.report do
File.readlines("2mrecords.csv").map!{|line| line.split(",")}.
終了
終了
ユーザー システム 合計 実質
12.797000 2.437000 15.234000 (106.319865)
ファイルを完全にダウンロードするのに106秒以上かかった。かなりの時間だ!しかし、このプロセスは 地図 メソッドに 同時に ループだ:
require 'benchmark'
ベンチマーク.bm do |x|
x.report do
file = File.open("2mrecords.csv", "r")
while line = file.gets
line.split(",")
終了
終了
終了
ユーザー システム 合計 実質
6.078000 0.250000 6.328000 ( 6.649422)
以来、ランタイムは大幅に短縮された。 地図 のように、特定のクラスに属するメソッドです。 Hash#map または アレイ#mapここで ルビー は、実行されている限り、解析されたファイルのすべての行をメモリー内に保存する。 Rubyのガベージコレクタ は、それらのイテレータが完全に実行される前にメモリを解放することはない。しかし、一行ずつ読むと、GCは不要なときに前の行からメモリを再配置する。
これは前回の延長線上で、より一般的な例である。前述したように ルビー イテレーターはオブジェクト・メソッドであり、実行されている間はメモリを解放しない。小規模なものでは、この違いは無意味である(そして、例えば 地図 の方が読みやすい)。しかし、より大きなデータセットになると、より基本的なループに置き換えることを常に検討するのがよいだろう。下の例のように:
numberofelements = 10000000
randoms = Array.new(numberofelements) { rand(10) }.
randoms.eachは|line|を行う。
#何かする
終了
とリファクタリング後:
numberofelements = 10000000
randoms = Array.new(numberofelements) { rand(10) }.
while randoms.count > 0
line = randoms.shift
#何かをする
終了
"`
これは簡単だが特に役に立つヒントだ。裏で+=演算子を使って文字列を別の文字列に追加する場合。 ルビー は追加のオブジェクトを作成する。つまり、これだ:
a = "X"
b = "Y"
a += b
つまり、こういうことだ:
a = "X"
b = "Y"
c = a + b
a = c
オペレーターがそれを回避し、メモリーを節約する:
a = "X"
b = "Y"
a << b
について Railsフレームワーク をたくさん持っている。おまけ「を最適化することができる。 コード 手間をかけずに、素早く。
PostとAuthorという2つの関連モデルがあると仮定しよう:
class Author < ApplicationRecord
has_many :投稿
終了
クラス Post < ApplicationRecord
所属 :author
終了
コントローラですべての投稿を取得し、作者とともにビューにレンダリングしたい:
コントローラー
defインデックス
posts = Post.all.limit(20)
終了
ビュー
とする。
<%= post.
%
コントローラーで アクティブレコード は、投稿を見つけるためのクエリーを1つだけ作成します。しかし後で、それぞれの作者を検索するためにさらに20個のクエリを生成することになり、さらに時間がかかります!幸いなことに、Railsにはこれらのクエリを1つにまとめる簡単なソリューションが用意されています。Railsの を含む。 メソッドを使えば、コントローラをこう書き換えることができる:
def index
@posts = Post.all.includes(:author).limit(20)
終了
今のところ、必要なデータだけが1つのクエリーに取り込まれる。
また、次のような他の宝石を使うこともできる。 弾丸 を使用して、プロセス全体をカスタマイズすることができます。
ActiveRecordの処理速度を上げるもうひとつの便利なテクニックは、現在の目的に必要な属性だけを呼び出すことだ。これは、アプリが成長し始め、テーブルごとのカラム数が増えてきたときに特に有効です。
先ほどのコードを例にして、著者から名前を選択するだけでいいと仮定してみよう。そこで、コントローラを書き直します:
def index
@posts = Post.all.includes(:author).select("name").limit(20)
終了
ここで、必要な属性以外のすべての属性をスキップするようにコントローラに指示する。
以前の例とは別の投稿用のパーシャルを作りたいとします:
<%
@posts.eachは|post|を行う。
.
<%
一見すると、このコードは正しいように見える。しかし、レンダリングする記事の数が多くなると、処理全体が著しく遅くなる。これは レールズ はもう一度新しいイテレーションでパーシャルを呼び出します。この問題は コレクション が特徴だ:
<%=レンダー@posts %
今すぐだ、 レールズ は自動的にどのテンプレートを使うべきかを判断し、一度だけ初期化する。
例えば、電子メールの送信、統計情報の収集、定期的なレポートの提供などである。
サイドキック はバックグラウンド処理に最もよく使われるgemである。これは レディス を使ってタスクを保存することができる。また、バックグラウンド・プロセスのフローを制御したり、別々のキューに分割したり、それぞれのキューのメモリ使用量を管理したりすることもできる。
レールズ は、あなたの生活を楽にし、開発プロセスを加速させるだけでなく、アプリケーションのパフォーマンス速度を向上させる膨大な数のgemを開発しました。DeviseやPunditのようなgemは通常、その速度に関して十分にテストされており、同じ目的のためにカスタムで書かれたコードよりも高速かつ安全に動作します。
改善に関するご質問 Railsのパフォーマンスリーチ The Codestエンジニア 疑問点を相談するために。
続きを読む