Lukuisista eduistaan huolimatta Ruby on Rails:tä pidetään edelleen suhteellisen hitaana web-kehyksenä. Me kaikki tiedämme, että Twitter on jättänyt Railsin Scalan hyväksi. Muutamalla näppärällä parannuksella voit kuitenkin ajaa sovelluksesi huomattavasti nopeammin!
Ruby First
Ruby on vahvasti oliosuuntautunut kieli. Itse asiassa (lähes) kaikki Ruby on objekti. Tarpeettomien objektien luominen voi aiheuttaa ohjelmallesi paljon ylimääräistä muistinkäyttöä, joten sitä on vältettävä.
Eroa mitataan käyttämällä memory_profiler helmi ja sisäänrakennettu Benchmark-moduuli ajan suorituskyvyn mittaamiseen.
Käytä bang! -metodeja merkkijonoille
vaatia "memory_profiler"
report = MemoryProfiler.report do
data = "X" * 1024 * 1024 * 100
data = data.downcase
end
report.pretty_print
Alla olevassa luettelossa luotiin 100 Mt:n merkkijono ja vähennettiin jokainen sen sisältämä merkki. Vertailulaskelmamme antaa seuraavan raportin:
Yhteensä myönnetty: 210765044 tavua (6 objektia)
Jos kuitenkin korvataan rivi 6 seuraavasti:
data.downcase!
Lue tiedostoja rivi riviltä
Oletettavasti meidän on haettava valtava 2 miljoonan tietueen kokoelma csv-tiedostosta. Tyypillisesti se näyttäisi tältä:
vaatia 'benchmark'
Benchmark.bm do |x|
x.report do
File.readlines("2mrecords.csv").map! {|line| line.split(",")}
end
end
käyttäjä järjestelmä yhteensä todellinen
12.797000 2.437000 15.234000 (106.319865)
Tiedoston lataaminen kokonaisuudessaan kesti yli 106 sekuntia. Aika paljon! Voimme kuitenkin nopeuttaa tätä prosessia korvaamalla tiedoston kartta! menetelmä yksinkertaisella kun taas silmukka:
vaatia 'benchmark'
Benchmark.bm do |x|
x.report do
file = File.open("2mrecords.csv", "r")
while line = file.gets
line.split(",")
end
end
end
käyttäjä järjestelmä yhteensä todellinen
6.078000 0.250000 6.328000 ( 6.649422)
Juoksuaika on nyt laskenut huomattavasti, koska kartta! menetelmä kuuluu tiettyyn luokkaan, kuten Hash#map tai Array#map, jossa Ruby tallentaa jokaisen jäsennetyn tiedoston rivin muistiin niin kauan kuin se suoritetaan. Rubyn roskienkerääjä ei vapauta muistia ennen kuin iteraattorit on suoritettu kokonaan. Sen lukeminen rivi riviltä kuitenkin GC:n avulla siirtää muistia edellisiltä riveiltä, kun se ei ole tarpeen.
Tämä on jatkoa edelliselle kohdalle, ja esimerkkinä on yleisempi esimerkki. Kuten mainitsin, Ruby iteraattorit ovat objektimetodeja, eivätkä ne vapauta muistia niin kauan kuin niitä suoritetaan. Pienessä mittakaavassa ero on merkityksetön (ja metodit kuten esim. kartta vaikuttaa luettavammalta). Suurempien tietokokonaisuuksien kohdalla on kuitenkin aina syytä harkita sen korvaamista yksinkertaisemmilla silmukoilla. Kuten alla olevassa esimerkissä:
numberofelements = 10000000
randoms = Array.new(numberofelements) { rand(10) }
randoms.each do |line|
#ehdä jotain
end
ja refaktoroinnin jälkeen:
numberofelements = 10000000
randoms = Array.new(numberofelements) { rand(10) }
while randoms.count > 0
line = randoms.shift
#ehdä jotain
end
"`
Käytä String::<< -menetelmää
Tämä on nopea mutta erityisen hyödyllinen vinkki. Jos liität yhden merkkijonon toiseen käyttämällä +=-operaattoria taustalla. Ruby luo ylimääräisen objektin. Joten tämä:
a = "X"
b = "Y"
a += b
Tarkoittaa oikeastaan tätä:
a = "X"
b = "Y"
c = a + b
a = c
Operaattori välttäisi sen ja säästäisi muistia:
a = "X"
b = "Y"
a << b
Puhutaan Railsista
The Rails-kehys on runsaasti "gotchas", jonka avulla voit optimoida koodi nopeasti ja ilman suurempia lisäponnistuksia.
Eager Loading eli n+1-kyselyongelma.
Oletetaan, että meillä on kaksi toisiinsa liittyvää mallia, Post ja Author:
class Author < ApplicationRecord
has_many :posts
end
class Post < ApplicationRecord
belongs_to :author
end
Haluamme noutaa kaikki viestit ohjaimessamme ja näyttää ne näkymässä tekijöineen:
ohjain
def index
@posts = Post.all.limit(20)
end
view
Ohjaimessa, ActiveRecord luo vain yhden kyselyn, jolla löydämme viestit. Myöhemmin se käynnistää kuitenkin vielä 20 muuta kyselyä kunkin kirjoittajan löytämiseksi, mikä vie ylimääräistä aikaa! Onneksi Railsissa on nopea ratkaisu näiden kyselyjen yhdistämiseen yhdeksi kyselyksi. Käyttämällä sisältää metodia, voimme kirjoittaa ohjaimemme uudelleen näin:
def index
@posts = Post.all.includes(:author).limit(20)
end
Toistaiseksi vain tarvittavat tiedot haetaan yhteen kyselyyn.
Voit käyttää myös muita jalokiviä, kuten esim. bullet muokata koko prosessia.
Soita vain mitä tarvitset
Toinen käyttökelpoinen tekniikka ActiveRecordin nopeuden lisäämiseksi on kutsua vain niitä attribuutteja, jotka ovat välttämättömiä tämänhetkisen käyttötarkoituksesi kannalta. Tämä on erityisen hyödyllistä, kun sovelluksesi alkaa kasvaa ja taulukkokohtaisten sarakkeiden määrä kasvaa.
Otetaan edellinen koodimme esimerkkinä ja oletetaan, että meidän on valittava vain nimet kirjoittajista. Voimme siis kirjoittaa ohjaimemme uudelleen:
def index
@posts = Post.all.includes(:author).select("name").limit(20)
end
Nyt annamme ohjaimellemme ohjeen ohittaa kaikki muut attribuutit paitsi sen, jota tarvitsemme.
Renderöi osatekijät oikein
Oletetaan, että haluamme luoda erillisen osittaisen osion edellisissä esimerkeissä mainituille viesteillemme:
Ensi silmäyksellä tämä koodi näyttää oikealta. Kun renderöitävien viestien määrä on kuitenkin suurempi, koko prosessi on huomattavasti hitaampi. Tämä johtuu siitä, että Kiskot kutsuu osittaisen toistomme uudella iteraatiolla jälleen kerran. Voimme korjata sen käyttämällä kokoelmat ominaisuus:
Nyt, Kiskot selvittää automaattisesti, mitä mallia tulisi käyttää, ja alustaa sen vain kerran.
Käytä taustakäsittelyä
Jokainen prosessi, joka on aikaa vievämpi eikä ole ratkaisevan tärkeä nykyiselle prosessivirrallesi, voidaan katsoa sopivaksi taustakäsittelyyn, esimerkiksi sähköpostien lähettäminen, tilastojen kerääminen tai säännöllisten raporttien laatiminen.
Sidekiq on yleisimmin käytetty helmi taustakäsittelyyn. Se käyttää Redis tehtävien tallentamiseen. Sen avulla voit myös hallita taustaprosessien kulkua, jakaa ne erillisiin jonoihin ja hallita muistin käyttöä kunkin prosessin osalta.
Kirjoita vähemmän koodia, käytä enemmän helmiä
Kiskot on keksinyt valtavan määrän helmiä, jotka paitsi helpottavat elämääsi ja nopeuttavat kehitysprosessia, myös lisäävät sovelluksesi suorituskykyä. Devisen tai Punditin kaltaiset jalokivet ovat yleensä hyvin testattuja nopeutensa suhteen ja toimivat nopeammin ja varmemmin kuin samaa tarkoitusta varten räätälöity koodi.
Jos sinulla on kysyttävää Railsin suorituskyky, reach Codest-insinöörit ulos kuulemaan epäilyksiäsi.