Flutter / واجهات شاملة وأدلة الأهداف / الدرس 15
القياس والعزل وكلفة العرض
حدّد المرحلة المكلفة قبل تغيير الشيفرة واعزل العمل الحسابي حين تبرر فائدته كلفة النقل.
في هذه الصفحة
أهداف الدرس
- قِس التفاعل على هدف ممثل
- ميّز البناء والتخطيط والرسم
- تجنب العمل النقي المكرر قبل إضافة التزامن
قِس التفاعل على هدف ممثل
يحتاج تقرير الأداء إلى تفاعل محدد وحجم بيانات ممثل وعتاد هدف ونمط بناء ومقياس مرصود. يضيف debug أدوات تشخيص ولا يمثل خط أساس موثوقا لأداء الإصدار. استخدم أدوات profile المدعومة للهدف وافحص السلوك المتكرر لا إطارا سريعا استثنائيا. وتختلف مهل الإطارات باختلاف معدل تحديث الشاشة، لذا يضلل اعتماد ميزانية عامة واحدة. سجّل هل يعاني المستخدم تأخر الإدخال أو التحميل الأول أو تقطع التمرير أو زيادة الذاكرة؛ فهذه أعراض بأسباب مختلفة وليست كلها مجرد تطبيق بطيء.
ميّز البناء والتخطيط والرسم
قد تمنع مهمة Dart طويلة معالجة أحداث الواجهة في الوقت المناسب. وقد يستهلك التخطيط المعقد وقتا رغم بساطة المنطق. وقد يكون الرسم مكلفا بسبب صور كبيرة أو مؤثرات واسعة أو قص أو طبقات خارج الشاشة. استخدم التتبع لتحديد المرحلة بدلا من اعتبار كل تقطع دليلا على كثرة بناء العناصر. قد تزيد إضافة RepaintBoundary في كل مكان كلفة الموارد ولا تصلح فك JSON المتزامن. وبالمثل لا يقلل نقل حساب إلى isolate من مؤثر بصري مكلف بلا داع. طابق التدخل مع الدليل المقاس.
تجنب العمل النقي المكرر قبل إضافة التزامن
يحسب المقتطف الأول قائمة مرشحة مرة واحدة من لقطة المدخلات الحالية. لدى مالك العنصر اشتقها عند تغير المدخل ذي الصلة، أو استخدم مخزنا مبررا يفهرس بكل الاعتماديات. لا تفهرس بطول القائمة وحده، فقد يتغير المحتوى دون الطول. وتجنب حفظ قوائم وسيطة كبيرة إلى أجل غير محدد مبكرا. قد يكفي تبسيط خوارزمية أو نقل حساب من رد كل صف. أثبت الصحة بمدخلات فارغة وصغيرة وكبيرة ممثلة قبل تقرير ضرورة التزامن.
List<int> visibleScores(List<int> scores, int minimum) =>
scores.where((score) => score >= minimum).toList(growable: false);
void main() {
print(visibleScores([3, 8, 5, 9], 6));
print(visibleScores([], 6));
}
[8, 9]
[]
الترشيح خطي في حجم المدخل ويحفظ ترتيبه. لا يبرر المثال الصغير isolate أو ادعاء أداء.
استخدم العزل بعقد رسائل صريح
لـ isolates في Dart ذاكرة منفصلة وتتواصل برسائل مدعومة بدلا من مشاركة الحالة العادية القابلة للتعديل. في أهداف Dart الأصلية المدعومة تستطيع compute تشغيل رد مناسب بعيدا عن isolate الواجهة؛ ويختلف سلوك الويب ولا يضمن التوازي نفسه. يبقي المقتطف الثاني المدخل والناتج بسيطين. لبدء العزل والتسلسل أو النسخ وتسليم النتيجة كلفة، لذا قد يكون نقل مهمة صغيرة أبطأ إجمالا. تجنب التقاط شبكة كائنات كبيرة أو محاولة إرسال BuildContext أو وحدات تحكم أو موارد منصة اعتباطية كمدخل.
import 'package:flutter/foundation.dart';
int sumSquares(List<int> values) =>
values.fold<int>(0, (total, value) => total + value * value);
Future<int> calculate() => compute(sumSquares, <int>[2, 3, 4]);
// await calculate() -> 29
The calculation returns 29; execution placement depends on the target.
يستخدم رد النداء مجموعة قيم أولية قابلة للإرسال. لا يدّعي تسريعا مقاسا أو تنفيذا أصليا على الويب.
أدر الصور والذاكرة كميزانية مستقلة
قد يتحول ملف صورة مضغوط إلى مخزن بكسلات أكبر كثيرا. وقد يهدر عرض صور كاملة الدقة كمصغرات صغيرة الذاكرة ووقت الفك. راجع أبعاد الفك المناسبة وسياسة التخزين ومسار الصور على الهدف بدلا من لوم عدد العناصر وحده. وقد تحتفظ وحدات التحكم والاشتراكات والقوائم بالبيانات بعد إغلاق الشاشات. راقب الذاكرة عبر دورات فتح وإغلاق لتمييز استقرار المخزن من النمو المستمر. ولا تفرض حدود تخزين اعتباطية دون قياس المحتوى وقيود الهدف.
قارن قبل التغيير وبعده بالحمل نفسه
غيّر سببا مشتبها واحدا وأعد التفاعل نفسه وقارن التتبعات والصحة. ثبّت البيانات والهدف ونمط البناء وأدوات القياس. قد يخفي متوسط أسرع تأخرا أسوأ في الحالات البطيئة أو كلفة ذاكرة جديدة، فافحص المقاييس ذات الصلة بالمهمة. احفظ اختبارات الترتيب والإلغاء والنتائج المتقادمة عند إدخال الحساب غير المتزامن. قد تصل نتيجة isolate بعد تقادم المالك أو المدخل. ولا تبلغ تحسنا إلا بقياس فعلي؛ فنتائج الحساب الصغيرة في الدورة توضح الصحة ولا تقدم معيار جهاز.
الأخطاء الشائعة وإصلاحها
يظل الإدخال متجمدا رغم انتظار دالة حسابية
- لماذا يحدث؟
- لم تنقل async العمل المتزامن خارج isolate الواجهة.
- كيف تصلحه؟
- قِس المهمة وبسّطها ثم اعزل العمل المناسب إذا تبرر.
- كيف تتجنب تكراره؟
- ميّز الجدولة من التنفيذ المتوازي.
يعيد المخزن بيانات ترشيح متقادمة
- لماذا يحدث؟
- أغفل مفتاح المخزن اعتمادا مثل العتبة أو المحتوى.
- كيف تصلحه؟
- افهرس بكل المدخلات الثابتة ذات الصلة أو أبطل لدى مالك واحد.
- كيف تتجنب تكراره؟
- اختبر تغير المحتوى مع ثبات الطول وتغير المرشحات.
يُعمم ادعاء العزل الأصلي على الويب
- لماذا يحدث؟
- تجاهل الاختلاف الخاص بالهدف في compute.
- كيف تصلحه؟
- اقرأ سلوك الهدف المدعوم واذكره صراحة.
- كيف تتجنب تكراره؟
- اربط القياسات والادعاءات بالهدف الفعلي.
اختبر فهمك
1. لماذا لا يرجح أن يفيد نقل مجموع أربعة أعداد إلى compute؟
اعرض الحل المشروح
الحساب صغير أمام كلفة الجدولة والرسائل. يشرح المثال الحد لا التسريع. قِس عملا كبيرا ممثلا أولا وبسّط الحساب غير الضروري وقارن زمن الاستجابة المرئي كاملا قبل اعتماد التزامن.
2. يرتفع عمل الرسم أثناء تقطع التمرير بينما يبقى عمل Dart منخفضا. ماذا تفحص؟
اعرض الحل المشروح
افحص الصور والمؤثرات المكلفة والقص والطبقات خارج الشاشة ونطاق إعادة الرسم في التتبع. لا يرجح أن يعالج تعديل مرشح نقي أو إضافة عزل تلك المرحلة. غيّر سببا بصريا واحدا وقارن حمل التمرير نفسه.
أهم ما تعلمته
- قِس التفاعل على هدف ممثل
- قارن قبل التغيير وبعده بالحمل نفسه