هل الوحدة بطيئة؟ تنبيه LINQ

كثيرا ما يقال أن الوحدة بطيئة. لكن كم؟ أقوم بتطوير تطبيق Pixel Studio ، هذا محرر فن بكسل. بالنسبة له ، كتبت تنفيذي لصيغة GIF. العملية الأكثر استهلاكًا للوقت هي تشفير GIF ، أي خوارزمية ضغط LZW. دعونا نرى كيف تتعامل الوحدة مع هذا.

الصورة

أولاً ، سأوضح على الفور سبب وجوب كتابة مكتبتي الخاصة. نعم ، كل شيء بسيط ، مكتبة System.Windows.Media.Imaging ، التي تحتوي على GifBitmapEncoder الرائع ، لا يمكن توصيلها بـ Unity. لذلك قرأت مقالات على المحور عن GIF ، وأخذت المواصفات وجعلت GIF الخاص بي مع لعبة ورق.

بالطبع ، بدأت كتابة وتصحيح المكتبة في Visual Studio ، في تطبيق وحدة التحكم. سأحذف هذه اللحظة ، كانت مملة وطويلة لتصحيحها ، استغرق الأمر 3 أيام. في مثل هذه الخوارزميات ، لم يكن لدي خبرة ، وعادة ما أقوم بالألعاب. حسنًا ، المكتبة جاهزة. على سبيل المثال ، يتم تشفير اختبار GIF "الثقيل" في 200 إطارًا ودقة 256 × 256 في 15 ثانية (Ryzen 7 ، بالطبع ، على أجهزتي). لقد فكرت كثيرًا ، وبمساعدة الرجل المحترم ، جعلت عملية الضغط موازية (مثل الوحدة يجب أن تدعم الخيوط). تم ترميز اختبار GIF في 5 ثوانٍ. عظيم!

مجرد نسخ جميع التعليمات البرمجية المصدر إلى الوحدة للتحقق مما إذا كان يعمل. يستغرق اختبار ترميز GIF 120 ثانية. في الوضع متعدد الخيوط (نعم ، تعمل الخيوط في Unity ، الشيء الرئيسي هو عدم لمس واجهة المستخدم) تشفير gif يستغرق 180 ثانية. Facepalm.

جوجل - المشكلة ، كما اتضح ، شائعة. وفقًا لتقارير مشابهة ، فإن كود الخوارزمية في Unity يعمل بشكل أبطأ من 10 إلى 20 مرة. يُزعم أن هذا مرتبط بتنفيذ آخر لمجموعة القمامة ومحرر الضباب Overhead. الوضع في التجميعات (Windows ، Android) مشابه. في تجميع .exe ، على سبيل المثال ، يعمل بشكل أسرع قليلاً ، بنسبة 20٪.

سؤال للقراء - هل أفعل شيئًا خاطئًا ، أم هناك مشكلة؟

رابط لتطبيق GIF المهتمين: GitHub . تمت كتابة المكتبة تحت C # الإصدار 6 و .NET 3.5 لتكون متوافقة مع الإصدارات القديمة من Unity. يمكن تحويل المشروع إلى .NET 4.0 ، ثم ستعمل ThreadPool بشكل أسرع.

تحديث: شكرا للتعليقات! كل شيء أصبح مربكًا بعض الشيء: كل من الخيوط مع الأقفال وتنفيذ المنحنى. لذلك قمت بإعداد حالة بسيطة - عملية التشغيل عبر مصفوفة في LINQ. وبالتحديد ، يتم تنفيذ هذه العملية أثناء ضغط LZW (يوجد فقط فحص رئيسي في القاموس).

الصورة

ننفذ في تطبيق وحدة التحكم - 5 مللي ثانية.
يعمل في الوحدة - 2100 مللي ثانية.

تحديث: تم العثور على جزء من المشكلة في LINQ. على سبيل المثال ، استدعاء يحتوي على أبطأ عدة مرات من Array.IndexOf. LINQ رائع ، إنه يوفر الوقت ويجعل الكود أكثر جمالا. ولكن ليس في المهام التطبيقية مثل العمل مع صفائف كبيرة من الكائنات. ينطبق هذا على تطبيق LINQ محدد في الوحدة.

UPD: تم تحسين خوارزمية ضغط LZW ، وإزالة مفاتيح السلسلة في القاموس. تمت إزالة LINQ للمجموعات الكبيرة حيثما أمكن. لم أتطرق إلى تطبيق تعدد مؤشرات الترابط. وسار كل شيء ، حتى على Android. بالطبع ، يبقى الفرق بين سرعة تطبيق وحدة التحكم ، ولكنه ليس كبيرًا.

شكر خاص لـ WNeZRoS للمساعدة في تحسين الشفرة ولجميع المشاركين في المناقشة! على الرغم من أن سبب المكابح في LINQ لا يزال بدون حل.

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


All Articles