على الرغم من مزاياه العديدة، إلا أن Ruby on Rails لا يزال يعتبر إطار عمل ويب بطيء نسبيًا. نعلم جميعًا أن تويتر قد ترك Rails لصالح سكالا. ومع ذلك، مع بعض التحسينات الذكية يمكنك تشغيل تطبيقك بشكل أسرع بكثير!
روبي فيرست
روبي هي لغة موجهة للكائنات بشكل كبير. في الواقع، كل شيء (تقريبًا) في روبي كائن. قد يكلف إنشاء كائنات غير ضرورية برنامجك الكثير من الاستخدام الإضافي للذاكرة، لذا عليك تجنب ذلك.
تتطلب "ميموري_بروفيلر"
تقرير = MemoryProfiler.report.report do
البيانات = "X" * 1024 * 1024 * 1024 * 100
البيانات = data.downcase البيانات
النهاية
تقرير.pretty_print
في القائمة أدناه، أنشأنا سلسلة حجمها 100 ميغابايت وقمنا بتصغير كل حرف موجود فيها. يعطينا معيارنا التقرير التالي:
إجمالي المخصص 210765044 بايت (6 كائنات)
ومع ذلك، إذا استبدلنا السطر 6 بـ
data.downcase!
قراءة الملفات سطرًا تلو الآخر
من المفترض أننا نحتاج إلى جلب مجموعة بيانات ضخمة من 2 مليون سجل من ملف csv. عادة، سيبدو الأمر هكذا
تتطلب "معيار
Benchmark.bm do |x|
x.report do
File.readlines("2mrecords.csv").map! {||الخط|الخط.line.split("،")}
النهاية
النهاية
إجمالي نظام المستخدم الحقيقي
12.797000 2.437000 15.234000 (106.319865)
استغرقنا أكثر من 106 ثانية لتنزيل الملف بالكامل. كثيراً جداً! ولكن يمكننا تسريع هذه العملية عن طريق استبدال الخريطة مع طريقة بسيطة بينما حلقة:
تتطلب "معيار
Benchmark.bm do |x|
x.report do
ملف = file.open("2mrecords.csv", "r")
بينما السطر = file.gets
line.split("،")
النهاية
النهاية
النهاية
إجمالي نظام المستخدم الحقيقي
6.078000 0.250000 6.328000 ( 6.649422)
لقد انخفض وقت التشغيل الآن بشكل كبير منذ الخريطة ينتمي إلى فئة معينة، مثل خريطة Hash#map أو Array#mapحيث روبي سيخزن كل سطر من الملف المُحلل داخل الذاكرة طالما تم تنفيذه. جامع قمامة روبي لن يحرر الذاكرة قبل تنفيذ تلك المكررات بالكامل. ومع ذلك، فإن قراءتها سطرًا بسطر سيؤدي إلى نقل الذاكرة من الأسطر السابقة عندما لا يكون ذلك ضروريًا.
تجنب مكررات الأسلوب على المجموعات الكبيرة
هذه النقطة امتداد للنقطة السابقة مع مثال أكثر شيوعًا. كما ذكرت, روبي التكرارات هي طرائق كائنات ولن تحرر الذاكرة طالما أنها تُنفَّذ. على نطاق صغير، لا معنى للفرق (وطرق مثل الخريطة يبدو أكثر قابلية للقراءة). ومع ذلك، عندما يتعلق الأمر بمجموعات بيانات أكبر، من الجيد دائمًا التفكير في استبدالها بحلقات أساسية أكثر. كما في المثال أدناه:
عدد العناصر = 10000000
randoms = Array.new.new(numberofelements) { rand(10)}
randoms.every تفعل ||خط |
#فعل شيئًا ما
النهاية
وبعد إعادة الهيكلة
عدد العناصر = 10000000
randoms = Array.new.new(numberofelements) { rand(10)}
بينما randoms.count > 0
الخط = randoms.shift
1TP63فعل شيء ما
النهاية
"`
استخدم طريقة String::<<<
هذه نصيحة سريعة ومفيدة للغاية. إذا ألحقت سلسلة بأخرى باستخدام عامل التشغيل +=+= خلف الكواليس. روبي سينشئ كائنًا إضافيًا. إذن، هذا
أ = "س"
ب = "Y"
أ += ب
في الواقع هذا يعني هذا:
أ = "س"
ب = "Y"
ج = أ + ب
أ = ج
سيتجنب المشغل ذلك، مما يوفر لك بعض الذاكرة:
< أ = "س"
ب = "Y"
أ << ب
لنتحدث عن القضبان
إن إطار عمل القضبان يمتلك الكثير من "غيتشاس" التي من شأنها أن تسمح لك بتحسين الكود بسرعة وبدون بذل الكثير من الجهد الإضافي.
التحميل الحريص المعروف أيضًا باسم مشكلة الاستعلام n+1
دعنا نفترض أن لدينا نموذجين مرتبطين هما "المنشور" و"المؤلف":
فئة المؤلف <سجل التطبيق
لديه_كثير :المشاركات
نهاية
صنف منشور < سجل التطبيق
ينتمي_إلى :المؤلف
النهاية
نريد جلب جميع المنشورات في وحدة التحكم الخاصة بنا وعرضها في طريقة عرض مع مؤلفيها:
وحدة التحكم
تعريف الفهرس
@posts = Post.all.all.limit(20)
نهاية
عرض
في وحدة التحكم, أكتيف ريكورد سينشئ استعلامًا واحدًا فقط للعثور على مشاركاتنا. ولكن في وقت لاحق، سيؤدي ذلك أيضًا إلى تشغيل 20 استعلامًا آخر للعثور على كل مؤلف وفقًا لذلك - مما يستغرق وقتًا إضافيًا! لحسن الحظ، يأتي Rails بحل سريع لدمج هذه الاستعلامات في استعلام واحد. باستخدام تشمل يمكننا إعادة كتابة وحدة التحكم بهذه الطريقة:
تعريف الفهرس
@posts = Post.all.total.includes(:author).limit(20)
نهاية
في الوقت الحالي، سيتم جلب البيانات الضرورية فقط في استعلام واحد.
يمكنك أيضًا استخدام أحجار كريمة أخرى، مثل رصاصة لتخصيص العملية بأكملها.
اتصل بما تحتاج إليه فقط
أسلوب آخر مفيد لزيادة سرعة ActiveRecord هو استدعاء تلك السمات الضرورية فقط لأغراضك الحالية. هذا مفيد بشكل خاص عندما يبدأ تطبيقك في النمو ويزداد عدد الأعمدة في كل جدول أيضًا.
لنأخذ الشيفرة السابقة كمثال ونفترض أننا نحتاج فقط إلى تحديد الأسماء من المؤلفين. لذا، يمكننا إعادة كتابة وحدة التحكم الخاصة بنا:
<مؤشر التعريف
@posts = Post.all.all.includes(:author).select("name").limit(20)
نهاية
الآن نوجه وحدة التحكم لدينا لتخطي جميع السمات باستثناء تلك التي نحتاجها.
تقديم الجزئيات بشكل صحيح
لنفترض أننا نريد إنشاء جزء منفصل لمشاركاتنا من الأمثلة السابقة:
للوهلة الأولى، يبدو هذا الرمز صحيحًا. ومع ذلك، مع وجود عدد أكبر من المنشورات المراد تصييرها، ستكون العملية بأكملها أبطأ بكثير. هذا بسبب القضبان يستدعي الجزئي الخاص بنا بتكرار جديد مرة أخرى. يمكننا إصلاح ذلك باستخدام المجموعات الميزة:
الآن, القضبان سيكتشف تلقائيًا القالب الذي يجب استخدامه وتهيئته مرة واحدة فقط.
استخدام المعالجة الخلفية
يمكن اعتبار كل عملية تستغرق وقتًا أطول وليست حاسمة لتدفقك الحالي مرشحة جيدة للمعالجة في الخلفية، مثل إرسال رسائل البريد الإلكتروني أو جمع الإحصائيات أو تقديم تقارير دورية.
صدّيق هي الجوهرة الأكثر استخدامًا لمعالجة الخلفية. يستخدم ريديس لتخزين المهام. كما يسمح لك بالتحكم في تدفق عمليات الخلفية الخاصة بك، وتقسيمها إلى قوائم انتظار منفصلة وإدارة استخدام الذاكرة لكل منها.
اكتب كوداً برمجياً أقل، واستخدم المزيد من الأحجار الكريمة
القضبان جاء بعدد هائل من الأحجار الكريمة التي لا تجعل حياتك أسهل وتسرّع عملية التطوير فحسب، بل تزيد أيضًا من سرعة أداء تطبيقك. عادةً ما تكون الأحجار الكريمة مثل Devise أو Pundit مختبرة جيدًا فيما يتعلق بسرعتها وتعمل بشكل أسرع وأكثر أمانًا من التعليمات البرمجية المكتوبة خصيصًا لنفس الغرض.
في حالة وجود أي أسئلة لتحسين أداء القضبانالوصول إلى مهندسون The Codest الخروج لاستشارة شكوكك.