الأداء في iOS أو كيفية إلغاء تحميل الخيط الرئيسي. الجزء الأول



هناك العديد من الحيل والحيل التي تساعد على تحسين عمل تطبيقات iOS ، عندما يجب إكمال مهمة واحدة في 16.67 مللي ثانية. نخبرك بكيفية تفريغ سلسلة المحادثات الرئيسية والأدوات الأكثر ملاءمة لتتبع مكدس المكالمة فيها.


"يا شباب ، دعنا نتخيل أنه يمكنك تقليل وقت بدء التشغيل بمقدار 10 ثوانٍ. بضرب هذا في 5 ملايين مستخدم ، سيكون لدينا 50 مليون ثانية يوميًا. في غضون عام سيصل هذا إلى حوالي عشرة أرواح بشرية. لذلك ، إذا قمت بإجراء التنزيل الأولي بسرعة 10 ثوانٍ ، فسوف تنقذ عشرات الأرواح. إنه حقًا يستحق ذلك ، أليس كذلك؟ "

ستيف جوبز على الأداء (وقت بدء تشغيل كمبيوتر Apple II).


تستند المقالة على تقرير أعده مطور Fyusion iOS Luc Parham ، الذي تحدث في مؤتمر MBLT DEV International Mobile Developers Conference العام الماضي.


ستعقد MBLT DEV 2018 في موسكو في 28 سبتمبر. التذاكر هي الأرخص الآن. حسب التقاليد ، بينما تختار لجنة البرنامج التقارير ، يمكنك شراء تذاكر الطيور المبكرة لـ konf. انتهز هذه الفرصة الآن. اعتبارًا من 29 يونيو ، ستكون التذاكر أكثر تكلفة.


فقدان الإطار


ينفذ مؤشر الترابط الرئيسي التعليمات البرمجية المسؤولة عن أحداث نوع اللمس والعمل مع واجهة المستخدم. انه يجعل الشاشة. يتم تقديم معظم الهواتف الذكية الحديثة بسرعة 60 إطارًا في الثانية. وهذا يعني أنه يجب إكمال المهام في 16.67 مللي ثانية (1000 مللي ثانية / 60 إطارًا). لذلك ، التسارع في الخيط الرئيسي مهم.


إذا استغرقت بعض العمليات أكثر من 16.67 مللي ثانية ، يحدث فقدان الإطار تلقائيًا ، وسيلاحظ مستخدمو التطبيق ذلك عند تشغيل الرسوم المتحركة. في بعض الأجهزة ، يكون العرض أسرع ، على سبيل المثال ، على iPad Pro 2017 ، يبلغ معدل تحديث الشاشة 120 هرتز ، لذلك هناك 8 مللي ثانية فقط لإكمال العمليات في إطار واحد.


القاعدة رقم 1


CADisplayLink هو مؤقت خاص يبدأ أثناء المزامنة الرأسية (Vsync). تضمن المزامنة الرأسية عدم تخصيص أكثر من 16.67 مللي ثانية لعرض إطار. كشيك في AppDelegate ، يمكنك تسجيل CADisplayLink في حلقة التشغيل الرئيسية ، وبعد ذلك سيكون لديك وظيفة إضافية تقوم بإجراء العمليات الحسابية. يمكنك تتبع مدة التطبيق ومعرفة مقدار الوقت الذي انقضى منذ آخر إطلاق لهذه الوظيفة.


.


يحدث بدء التشغيل عندما تظهر الحاجة إلى العرض. إذا تم إجراء العديد من العمليات المختلفة التي أثقلت على الخيط الرئيسي ، فإن هذه الوظيفة تبدأ بتأخير 100 مللي ثانية. هذا يعني أن الكثير من العمل قد تم ، وفي تلك اللحظة كانت هناك خسارة في الموظفين.


هنا هو تطبيق Catstagram. أثناء تنزيل الصور ، يبدأ التطبيق في التباطؤ. نرى أن معدل الإطارات انخفض عند نقطة معينة ، واستمر وقت التحميل حوالي 200 مللي ثانية. يبدو أن شيئًا ما يستغرق وقتًا طويلاً.


.


لن يسعد المستخدمون بهذا ، خاصة إذا تم تشغيل التطبيق على الأجهزة القديمة ، مثل iPhone 5 أو طرازات iPod القديمة ، إلخ.


محلل الوقت


أداة مفيدة لتتبع مثل هذه المشكلات هي Time Profiler. الأدوات الأخرى مفيدة أيضًا ، ولكن في نهاية المطاف في Fyusion 90٪ من الوقت نستخدم Time Profiler. عادةً ، تتعلق المشاكل في أحد التطبيقات بـ ScrollView ، وهي مناطق تحتوي على نص وصور.


الصور مهمة. نقوم بفك تشفير تنسيق JPEG باستخدام UIImage . إنهم يفعلون ذلك ببطء ، ولا يمكننا تتبع أدائهم مباشرة. لا يحدث هذا فورًا بعد تعيين الصورة في UIImageView ، ولكن يمكنك رؤية هذه اللحظة من خلال التتبع في Time Profiler.


تنسيق النص هو نقطة مهمة أخرى. يهم عندما يحتوي التطبيق على كمية كبيرة من النص "المعقد" ، على سبيل المثال ، باللغة اليابانية أو الصينية. قد يستغرق حساب الأحجام الصحيحة للخطوط ذات النص وقتًا طويلاً.


يؤدي أيضًا ترميز الواجهة إلى إبطاء العرض في التطبيق. هذا ينطبق بشكل خاص على أداة AutoLayout. AutoLayout مناسب للاستخدام ، لكنه يبطئ التطبيق بشكل كبير مقارنة بالترميز اليدوي. علينا تقديم تنازلات. إذا قام AutoLayout بإبطاء التطبيق ، فقد يكون الوقت قد حان للتخلي عنه وتجربة أنواع أخرى من الترميز.


نمط التتبع




في شجرة المثال هذه ، يمكنك معرفة نوع العمل الذي تقوم به وحدة المعالجة المركزية. يمكنك تغيير نوع التتبع ، وإلقاء نظرة عليه من وجهة نظر الخيوط والمعالجات. عادة ما يكون الشيء الأكثر إثارة للاهتمام هو تقسيم التتبع إلى خيوط ومراقبة الخيط الرئيسي.


قد يبدو تحليل التتبع الأولي معقدًا. ليس من الممكن دائمًا معرفة ما FRunLoopDoSource0 الفور.


بالتفتيش على التتبع ، يمكنك فهم كيفية عمل النظام ، وبعد ذلك كل شيء منطقي. يمكنك تتبع تتبع المكدس وإلقاء نظرة على جميع عناصر النظام التي لم تكتبها. ولكن في الجزء السفلي هو شفرة المصدر الخاصة بك.


شجرة الاتصال


لنفترض أن لدينا تطبيقًا بسيطًا للغاية. يحتوي على الوظيفة الرئيسية التي تستدعي العديد من الوظائف الأخرى. إن جوهر عمل Time Profiler هو أنه يأخذ لقطات للحالة الحالية لتتبع المكدس بتردد واحد مللي ثانية (افتراضيًا). بعد ميلي ثانية أخرى ، يأخذ لقطة للتتبع. يطلق على الوظيفة الرئيسية ، التي تسمى الوظيفة " foo " ، والتي تسمى الوظيفة " bar ". يظهر تتبع المكدس الأولي في لقطة الشاشة أدناه. يتم جمع هذه البيانات معا. مقابل كل وظيفة ، يشار إلى رقم: 1 ، 1 ، 1.




هذا يعني أنه تم استدعاء كل من هذه الوظائف مرة واحدة. ثم ، بعد ميلي ثانية واحدة ، نحصل على لقطة أخرى للمكدس. هذه المرة تبدو متشابهة تمامًا ، لذلك تزداد جميع الأرقام بمقدار 1 ، ونحصل على 2 ، 2 ، 2.




خلال الملي ثانية الثالثة ، يبدو مكدس المكالمات مختلفًا قليلاً. الوظيفة الرئيسية تستدعي bar مباشرة. لذلك ، تتم إضافة وحدة أخرى إلى الوظيفة الرئيسية والدالة " bar " ، وتصبح قيمتهما 3. بعد ذلك ، يحدث الفصل. في بعض الأحيان تسمى الوظيفة الرئيسية " foo " مباشرة ، وفي بعض الأحيان يُطلق على " bar " مباشرة. حدث هذا مرة واحدة. تم استدعاء دالة من خلال وظيفة أخرى.


بعد ذلك ، تسمى إحدى الوظائف الأخرى ، والتي تسمى الوظيفة الثالثة. نرى أن وظيفة " baz " كانت تسمى مرتين. لكن هذه الوظيفة غير مهمة لدرجة أنها تسمى أسرع من مللي ثانية واحدة.


عند استخدام Time Profiler ، من المهم أن تتذكر أنها لا تُظهر فترات زمنية محددة. لا يعرض وقت التنفيذ الدقيق للدالة. ويذكر فقط عدد المرات التي تظهر فيها في الصور ، والتي لا تعطي سوى قيمة تقريبية لمدة كل وظيفة. نظرًا لأن بعض العمليات سريعة بما فيه الكفاية ، لا يتم عرضها أبدًا على الصور.




عند تبديل المكالمات إلى وضع وحدة التحكم ، يمكنك مشاهدة ومقارنة كل لحظات انخفاض معدل الإطارات. في المثال ، حدث فقد الإطار عدة مرات وتم تنفيذ عمليات مختلفة.




سيؤدي النقر مع الضغط على مفتاح Alt على macOS إلى توسيع القسم والأقسام الفرعية ، وليس فقط القسم المحدد. سيتم فرزها حسب مقدار العمل المنجز. في 90٪ من الحالات ، يأتي CFRunLoopRun ، يليه الاسترجاعات.


يعتمد هذا التطبيق بالكامل على دورة تنفيذ مهمة تشغيل حلقة واحدة. هناك دورة متكررة إلى ما لا نهاية ، وفي كل تكرار ، يتم إطلاق عمليات الاستدعاء. إذا نظرت إلى عمليات إعادة الاتصال هذه ، يمكنك تمييز الاختناقات العليا.


بعد النظر في هذه التحديات بمزيد من التفصيل ، لن تفهم على الأرجح ما يفعلونه. يمكن أن تكون هذه ، مقدم الصور ، IO.




هناك خيار يسمح لك بإخفاء مكتبات النظام. هم في الواقع مجالات المشكلة في التطبيق.


هناك مقاييس تُظهر من حيث النسبة المئوية مقدار العمل الذي تؤديه وظيفة أو عملية معينة. إذا نظرنا إلى هذا المثال ، سنرى هنا القيمة - 34٪. هذه هي عملية Apple jpeg_decode_image_all . بعد الدراسة ، يصبح من الواضح أن فك تشفير صور JPEG يحدث في الخيط الرئيسي ، وفي معظم الحالات يكون هذا هو سبب فقدان الإطار.




القاعدة رقم 2


بشكل عام ، يجب أن يتم فك تشفير صور jpeg في الخلفية. يمكن لمعظم مكتبات الجهات الخارجية (AsyncDisplayKit و SDWebImage وما إلى ذلك) القيام بذلك بشكل افتراضي. إذا كنت لا ترغب في استخدام الإطارات ، يمكنك إجراء فك التشفير يدويًا. للقيام بذلك ، يمكنك كتابة ملحق عبر UIImage حيث تقوم بإنشاء سياق ورسم صورة يدويًا.




عند تنفيذ هذه العملية ، يمكنك استدعاء وظيفة decodeImage وليس من الخيط الرئيسي. ستعرض دائمًا صورة تم فك تشفيرها. لا توجد طريقة للتحقق مما إذا كانت صورة UIImage معينة قد اجتازت فك التشفير ، لذلك يجب عليك دائمًا تمريرها من خلال هذه الطريقة. ولكن إذا قمت بتخزين البيانات بشكل صحيح ، فلن تكون هناك عمليات غير ضرورية في النظام.


من وجهة نظر فنية ، هذا أقل فعالية. يبدو أن استخدام فئة UIImageView محسن وفعال. ولكنه يقوم أيضًا بفك تشفير الأجهزة ، لذا فإن له عيوبه أيضًا. بهذه الطريقة ، سيتم فك تشفير صورك بشكل أبطأ. ولكن هناك أخبار جيدة - يمكنك فك شفرة الصورة بالطريقة المذكورة أعلاه وليس على الخيط الرئيسي ، ثم العودة إلى الخيط الرئيسي وتكوين الواجهة.




على الرغم من حقيقة أن هذه العملية تتطلب المزيد من الوقت ، فقد لا يتم إجراؤها على الخيط الرئيسي ، مما يعني أنها لا تتداخل مع نشاط المستخدم في التطبيق ، لأنها لا تبطئ تمرير الشريط. حل مربح.


تنبيهات نفاد الذاكرة


مع أي إشارة لانخفاض الذاكرة ، أريد حذف جميع البيانات غير المستخدمة الممكنة. ولكن إذا تم تنفيذ عمليات مختلفة على تدفقات الطرف الثالث ، فإن وضع صور JPEG المشفرة ذات الحجم المشفر عليها سيستهلك معظم المساحة الحرة.


حدثت مثل هذه المشكلة في تطبيق Fyuse. إذا كنت قد قمت بفك تشفير جميع صور JPEG الخاصة بي في دفق جهة خارجية ، ففي بعض الحالات ، على سبيل المثال ، على طرازات الهواتف القديمة ، سيؤدي هذا النظام إلى تعطيل التطبيق على الفور. ويرجع ذلك إلى حقيقة أن تدفقات مهام الجهات الخارجية لا تستجيب للتحذير من عدم كفاية الذاكرة من النظام ، مثل "مرحبًا ، احذف البيانات غير الضرورية!". يحدث الموقف التالي: تقوم أولاً بوضع كل هذه الصور في تدفقات الجهات الخارجية ، ثم يتعطل التطبيق باستمرار. إذا كانت سلاسل رسائل الطرف الثالث ترسل إشارات إلى سلسلة المحادثات الرئيسية حول ما يحدث في النظام ، فلن تحدث مثل هذه المشكلة.


اعمل بدون فشل




في الأساس ، الخيط الرئيسي هو قائمة انتظار تتكون من العمليات. عند العمل مع performSelectorOnMainThread:withObject:waitUntilDone: التابعة لجهات خارجية ، يمكنك كتابة الأمر performSelectorOnMainThread:withObject:waitUntilDone: in Objective-C. بفضلها ، سيتم وضع المهام في نهاية قائمة الانتظار على الخيط الرئيسي. لذلك ، إذا كان مؤشر الترابط الرئيسي مشغولاً في معالجة الإعلامات خارج الذاكرة ، فإن استدعاء هذا الأمر سيسمح لك بالانتظار حتى تتم معالجة جميع الإخطارات ، وعندها فقط تبدأ العملية المعقدة لتحميل البيانات ووضعها. في Swift ، يبدو هذا أبسط قليلاً. DispatchQueue.main.sync مساحة على مؤشر الترابط الرئيسي.


هنا مثال آخر. قمنا بتحرير الذاكرة وفك تشفير الصور في تدفقات الجهات الخارجية. أصبح التمرير البصري للشريط أفضل بكثير. ما زلنا نفقد الإطارات نظرًا لأننا نختبر iPod 5g. هذا هو واحد من أسوأ نماذج الاختبار لتلك التي لا تزال تدعم إصدارات iOS 10 و 11.




إذا واجهت هذا النوع من فقدان الإطار ، فلا يزال بإمكانك عرض الشريط. ومع ذلك ، لا تزال هناك عمليات تستمر في التسبب في فقدان الموظفين. هناك طرق أخرى لجعل التطبيق يعمل بشكل أسرع.


بالطبع ، ليس من السهل دائمًا تحسين التطبيق. ولكن إذا كانت لديك مهام تستغرق وقتًا طويلاً نسبيًا لإنجازها ، فيجب عليك وضعها في خيوط الخلفية. تأكد من أن هذه المهام لا تتعلق بواجهة المستخدم ، نظرًا لأن العديد من فئات UIKit ليست آمنة لمؤشر الترابط ، أي أنه لا يمكنك إنشاؤها في الواجهة الخلفية.


استخدم Core Graphics إذا كنت بحاجة إلى معالجة الصور في دفق جهة خارجية. لا تخفي عرض مكتبات النظام. تذكر تحذيرات نفاد الذاكرة.


مرحبًا بك في MBLT DEV 2018


تعال في 28 سبتمبر إلى المؤتمر الدولي الخامس لمطوري MBLT DEV 2018 في موسكو. المتحدثون الأولون موجودون بالفعل في الموقع ، ولا يزال أحدث الطيور المبكرة معروضًا للبيع. سترتفع أسعار التذاكر في 29 يونيو. اشترِ التذاكر الآن بأقل سعر.



اقرأ عن تنفيذ واجهة المستخدم في iOS ، واستخدام منحنيات Bezier وغيرها من الأدوات المفيدة في الجزء الثاني من المقالة ، والذي سننشره في 28 يونيو.

Source: https://habr.com/ru/post/ar415155/


All Articles