Παρά τα πολυάριθμα πλεονεκτήματά του, το Ruby on Rails εξακολουθεί να θεωρείται ένα σχετικά αργό διαδικτυακό πλαίσιο. Όλοι γνωρίζουμε ότι το Twitter εγκατέλειψε το Rails υπέρ της Scala. Ωστόσο, με μερικές έξυπνες βελτιώσεις μπορείτε να τρέξετε την εφαρμογή σας σημαντικά πιο γρήγορα!
Ruby First
Ruby είναι σε μεγάλο βαθμό αντικειμενοστραφής γλώσσα. Στην πραγματικότητα, (σχεδόν) τα πάντα στην Ruby είναι ένα αντικείμενο. Η δημιουργία περιττών αντικειμένων μπορεί να κοστίσει στο πρόγραμμά σας πολύ επιπλέον χρήση μνήμης, γι' αυτό πρέπει να το αποφύγετε.
Για να μετρήσουμε τη διαφορά, θα χρησιμοποιήσουμε ένα memory_profiler gem και μια ενσωματωμένη ενότητα Benchmark για τη μέτρηση της απόδοσης του χρόνου.
Χρήση μεθόδων bang! σε συμβολοσειρές
require "memory_profiler"
report = MemoryProfiler.report do
data = "X" * 1024 * 1024 * 100
data = data.downcase
end
report.pretty_print
Στην παρακάτω λίστα, δημιουργήσαμε μια συμβολοσειρά 100MB και υποβαθμίσαμε κάθε χαρακτήρα που περιέχεται σε αυτήν. Η συγκριτική μας μέτρηση μας δίνει την ακόλουθη αναφορά:
Συνολικά κατανεμημένο: (6 αντικείμενα)
Ωστόσο, αν αντικαταστήσουμε τη γραμμή 6 με:
data.downcase!
Ανάγνωση αρχείων γραμμή προς γραμμή
Υποτίθεται ότι πρέπει να αντλήσουμε μια τεράστια συλλογή δεδομένων 2 εκατομμυρίων εγγραφών από ένα αρχείο csv. Τυπικά, θα έμοιαζε ως εξής:
απαιτούν 'benchmark'
Benchmark.bm do |x|
x.report do
File.readlines("2mrecords.csv").map! {|line| line.split(",")}
end
end
χρήστης σύστημα συνολικό πραγματικό
12.797000 2.437000 15.234000 (106.319865)
Μας πήρε περισσότερα από 106 δευτερόλεπτα για να κατεβάσουμε πλήρως το αρχείο. Αρκετά! Μπορούμε όμως να επιταχύνουμε αυτή τη διαδικασία αντικαθιστώντας το χάρτη! μέθοδο με ένα απλό ενώ βρόχο:
απαιτούν 'benchmark'
Benchmark.bm do |x|
x.report do
file = File.open("2mrecords.csv", "r")
while line = file.gets
line.split(",")
end
end
end
χρήστης σύστημα συνολικό πραγματικό
6.078000 0.250000 6.328000 ( 6.649422)
Ο χρόνος εκτέλεσης έχει πλέον μειωθεί δραστικά από το χάρτη! μέθοδος ανήκει σε μια συγκεκριμένη κλάση, όπως Χάρτης Hash#map ή Array#map, όπου Ruby θα αποθηκεύει κάθε γραμμή του αναλυμένου αρχείου στη μνήμη για όσο διάστημα εκτελείται. Ο συλλέκτης σκουπιδιών της Ruby δεν θα αποδεσμεύσει τη μνήμη πριν εκτελεστούν πλήρως οι επαναλήπτες αυτοί. Ωστόσο, διαβάζοντάς το γραμμή προς γραμμή, το GC θα επανατοποθετήσει τη μνήμη από τις προηγούμενες γραμμές όταν δεν είναι απαραίτητο.
Αποφυγή επαναληπτών μεθόδου σε μεγαλύτερες συλλογές
Αυτό είναι μια επέκταση του προηγούμενου σημείου με ένα πιο συνηθισμένο παράδειγμα. Όπως ανέφερα, Ruby οι επαναλήπτες είναι μέθοδοι αντικειμένων και δεν απελευθερώνουν τη μνήμη όσο εκτελούνται. Σε μικρή κλίμακα, η διαφορά δεν έχει νόημα (και μέθοδοι όπως οι χάρτης φαίνεται πιο ευανάγνωστο). Ωστόσο, όταν πρόκειται για μεγαλύτερα σύνολα δεδομένων, είναι πάντα καλή ιδέα να εξετάσετε το ενδεχόμενο αντικατάστασής του με πιο βασικούς βρόχους. Όπως στο παρακάτω παράδειγμα:
numberofelements = 10000000
randoms = Array.new(numberofelements) { rand(10) }
randoms.each do |line|
#κάνει κάτι
τέλος
και μετά την αναδιαμόρφωση:
numberofelements = 10000000
randoms = Array.new(numberofelements) { rand(10) }
while randoms.count > 0
line = randoms.shift
#κάνει κάτι
τέλος
"`
Χρήση της μεθόδου String::<<
Αυτή είναι μια γρήγορη αλλά ιδιαίτερα χρήσιμη συμβουλή. Αν προσαρτήσετε ένα αλφαριθμητικό σε ένα άλλο χρησιμοποιώντας τον τελεστή += στο παρασκήνιο. Ruby θα δημιουργήσει πρόσθετο αντικείμενο. Έτσι, αυτό:
a = "X"
b = "Y"
a += b
Στην πραγματικότητα σημαίνει αυτό:
a = "X"
b = "Y"
c = a + b
a = c
Ο χειριστής θα το απέφευγε αυτό, εξοικονομώντας σας λίγη μνήμη:
a = "X"
b = "Y"
a << b
Ας μιλήσουμε για Rails
Το Πλαίσιο Rails διαθέτει άφθονο "gotchas" που θα σας επιτρέψει να βελτιστοποιήσετε το κωδικός γρήγορα και χωρίς μεγάλη πρόσθετη προσπάθεια.
Πρόθυμη φόρτωση ή αλλιώς πρόβλημα n+1 ερωτημάτων
Ας υποθέσουμε ότι έχουμε δύο συσχετιζόμενα μοντέλα, το Post και το Author:
class Author < ApplicationRecord
has_many :posts
end
class Post < ApplicationRecord
belongs_to :author
end
Θέλουμε να φέρουμε όλες τις δημοσιεύσεις στον ελεγκτή μας και να τις εμφανίσουμε σε μια προβολή με τους συγγραφείς τους:
ελεγκτής
def index
@posts = Post.all.limit(20)
end
προβολή
Στον ελεγκτή, ActiveRecord θα δημιουργήσει μόνο ένα ερώτημα για να βρει τις θέσεις μας. Αλλά αργότερα, θα ενεργοποιήσει άλλα 20 ερωτήματα για να βρει κάθε συγγραφέα αντίστοιχα - καταναλώνοντας επιπλέον χρόνο! Ευτυχώς, το Rails διαθέτει μια γρήγορη λύση για να συνδυάσετε αυτά τα ερωτήματα σε ένα μόνο. Χρησιμοποιώντας το περιλαμβάνει μέθοδο, μπορούμε να ξαναγράψουμε τον ελεγκτή μας με αυτόν τον τρόπο:
def index
@posts = Post.all.includes(:author).limit(20)
end
Προς το παρόν, μόνο τα απαραίτητα δεδομένα θα συγκεντρώνονται σε ένα ερώτημα.
Μπορείτε επίσης να χρησιμοποιήσετε άλλα πολύτιμα πετράδια, όπως σφαίρα για να προσαρμόσετε την όλη διαδικασία.
Καλέστε μόνο ό,τι χρειάζεστε
Μια άλλη χρήσιμη τεχνική για την αύξηση της ταχύτητας της ActiveRecord είναι η κλήση μόνο εκείνων των χαρακτηριστικών που είναι απαραίτητα για τους τρέχοντες σκοπούς σας. Αυτό είναι ιδιαίτερα χρήσιμο όταν η εφαρμογή σας αρχίζει να μεγαλώνει και αυξάνεται και ο αριθμός των στηλών ανά πίνακα.
Ας πάρουμε ως παράδειγμα τον προηγούμενο κώδικά μας και ας υποθέσουμε ότι πρέπει να επιλέξουμε μόνο ονόματα από τους συγγραφείς. Έτσι, μπορούμε να ξαναγράψουμε τον ελεγκτή μας:
def index
@posts = Post.all.includes(:author).select("name").limit(20)
end
Τώρα δίνουμε εντολή στον ελεγκτή μας να παραλείψει όλα τα χαρακτηριστικά εκτός από αυτό που χρειαζόμαστε.
Αποδώστε σωστά τα Partials
Ας πούμε ότι θέλουμε να δημιουργήσουμε ένα ξεχωριστό μερικό για τις αναρτήσεις μας από τα προηγούμενα παραδείγματα:
Με μια πρώτη ματιά, ο κώδικας αυτός φαίνεται σωστός. Ωστόσο, με μεγαλύτερο αριθμό αναρτήσεων προς απόδοση, η όλη διαδικασία θα είναι σημαντικά πιο αργή. Αυτό οφείλεται στο γεγονός ότι Ράγες επικαλείται και πάλι το μερικό μας με μια νέα επανάληψη. Μπορούμε να το διορθώσουμε χρησιμοποιώντας το συλλογές χαρακτηριστικό:
Τώρα, Ράγες θα καταλάβει αυτόματα ποιο πρότυπο πρέπει να χρησιμοποιηθεί και θα το αρχικοποιήσει μόνο μία φορά.
Χρήση επεξεργασίας στο παρασκήνιο
Κάθε διαδικασία που είναι πιο χρονοβόρα και όχι ζωτικής σημασίας για την τρέχουσα ροή σας μπορεί να θεωρηθεί καλή υποψήφια για επεξεργασία στο παρασκήνιο, π.χ. αποστολή μηνυμάτων ηλεκτρονικού ταχυδρομείου, συλλογή στατιστικών στοιχείων ή παροχή περιοδικών αναφορών.
Sidekiq είναι το πιο συχνά χρησιμοποιούμενο πετράδι για επεξεργασία στο παρασκήνιο. Χρησιμοποιεί Redis για την αποθήκευση εργασιών. Σας επιτρέπει επίσης να ελέγχετε τη ροή των διεργασιών σας στο παρασκήνιο, να τις χωρίζετε σε ξεχωριστές ουρές και να διαχειρίζεστε τη χρήση μνήμης για κάθε μία από αυτές.
Ράγες δημιούργησε έναν τεράστιο αριθμό πολύτιμων λίθων που όχι μόνο κάνουν τη ζωή σας ευκολότερη και επιταχύνουν τη διαδικασία ανάπτυξης, αλλά αυξάνουν επίσης την ταχύτητα απόδοσης της εφαρμογής σας. Gems όπως το Devise ή το Pundit είναι συνήθως καλά δοκιμασμένα όσον αφορά την ταχύτητά τους και λειτουργούν γρηγορότερα και ασφαλέστερα από τον κώδικα που έχει γραφτεί κατά παραγγελία για τον ίδιο σκοπό.
Σε περίπτωση οποιωνδήποτε ερωτημάτων για τη βελτίωση Απόδοση Rails, reach Μηχανικοί The Codest για να συμβουλευτείτε τις αμφιβολίες σας.