الأداء في .NET Core

الأداء في .NET Core

الأداء في .NET Core

أهلاً بكم! هذه المقالة عبارة عن مجموعة من أفضل الممارسات التي استخدمناها أنا وزملائي لفترة طويلة عند العمل في مشاريع مختلفة.

معلومات عن الجهاز الذي تم إجراء الحسابات عليه:BenchmarkDotNet=v0.11.5، نظام التشغيل=Windows 10.0.18362
وحدة المعالجة المركزية Intel Core i5-8250U بسرعة 1.60 جيجا هرتز (Kaby Lake R)، وحدة معالجة مركزية واحدة، 1 نوى منطقية و8 نوى فعلية
.NET Core SDK=3.0.100
[المضيف]: .NET Core 2.2.7 (CoreCLR 4.6.28008.02، CoreFX 4.6.28008.03)، 64 بت RyuJIT
النواة: .NET Core 2.2.7 (CoreCLR 4.6.28008.02، CoreFX 4.6.28008.03)، 64 بت RyuJIT
[المضيف]: .NET Core 3.0.0 (CoreCLR 4.700.19.46205، CoreFX 4.700.19.46214)، 64 بت RyuJIT
النواة: .NET Core 3.0.0 (CoreCLR 4.700.19.46205، CoreFX 4.700.19.46214)، 64 بت RyuJIT

الوظيفة=وقت التشغيل الأساسي=الأساسي

ToList vs ToArray والدورات


لقد خططت لإعداد هذه المعلومات مع إصدار .NET Core 3.0، لكنهم سبقوني، لا أريد سرقة مجد شخص آخر ونسخ معلومات الآخرين، لذلك سأشير فقط رابط لمقالة جيدة حيث يتم وصف المقارنة بالتفصيل.

بالأصالة عن نفسي، أريد فقط أن أقدم لكم قياساتي ونتائجي، لقد أضفت إليها حلقات عكسية لمحبي "أسلوب C++" في حلقات الكتابة.

رمز:

public class Bench
    {
        private List<int> _list;
        private int[] _array;

        [Params(100000, 10000000)] public int N;

        [GlobalSetup]
        public void Setup()
        {
            const int MIN = 1;
            const int MAX = 10;
            Random random = new Random();
            _list = Enumerable.Repeat(0, N).Select(i => random.Next(MIN, MAX)).ToList();
            _array = _list.ToArray();
        }

        [Benchmark]
        public int ForList()
        {
            int total = 0;
            for (int i = 0; i < _list.Count; i++)
            {
                total += _list[i];
            }

            return total;
        }
        
        [Benchmark]
        public int ForListFromEnd()
        {
            int total = 0;t
            for (int i = _list.Count-1; i > 0; i--)
            {
                total += _list[i];
            }

            return total;
        }

        [Benchmark]
        public int ForeachList()
        {
            int total = 0;
            foreach (int i in _list)
            {
                total += i;
            }

            return total;
        }

        [Benchmark]
        public int ForeachArray()
        {
            int total = 0;
            foreach (int i in _array)
            {
                total += i;
            }

            return total;
        }

        [Benchmark]
        public int ForArray()
        {
            int total = 0;
            for (int i = 0; i < _array.Length; i++)
            {
                total += _array[i];
            }

            return total;
        }
        
        [Benchmark]
        public int ForArrayFromEnd()
        {
            int total = 0;
            for (int i = _array.Length-1; i > 0; i--)
            {
                total += _array[i];
            }

            return total;
        }
    }

سرعات الأداء في .NET Core 2.2 و3.0 متطابقة تقريبًا. إليك ما تمكنت من الحصول عليه في .NET Core 3.0:

الأداء في .NET Core

الأداء في .NET Core

يمكننا أن نستنتج أن المعالجة التكرارية لمجموعة Array تكون أسرع بسبب التحسينات الداخلية والتخصيص الصريح لحجم المجموعة. ومن الجدير بالذكر أيضًا أن مجموعة القائمة لها مزاياها الخاصة ويجب عليك استخدام المجموعة الصحيحة اعتمادًا على الحسابات المطلوبة. حتى لو كتبت منطقًا للعمل مع الحلقات، فلا تنس أن هذه حلقة عادية وتخضع أيضًا للتحسين المحتمل للحلقة. تم نشر مقال على حبر منذ فترة طويلة: https://habr.com/ru/post/124910/. لا تزال ذات صلة ويوصى بقراءتها.

رمي

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

رمز:

        public bool ContainsHash()
        {
            bool result = false;
            foreach (var file in _files)
            {
                var extension = Path.GetExtension(file);
                if (_hash.Contains(extension))
                    result = true;
            }

            return result;
        }

        public bool ContainsHashTryCatch()
        {
            bool result = false;
            try
            {
                foreach (var file in _files)
                {
                    var extension = Path.GetExtension(file);
                    if (_hash.Contains(extension))
                        result = true;
                }
                
                if(!result) 
                    throw new Exception("false");
            }
            catch (Exception e)
            {
                result = false;
            }

            return result;
        }

النتائج في .NET Core 3.0 وCore 2.2 لها نتيجة مماثلة (.NET Core 3.0):

الأداء في .NET Core

الأداء في .NET Core

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

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

لا ينبغي عليك كتابة بناء استثناء جديد () إذا لم يكن هذا الموقف استثنائيًا. التعامل مع الاستثناء وطرحه أمر مكلف للغاية !!!

ToLower، ToLowerInvariant، ToUpper، ToUpperInvariant

على مدى 5 سنوات من الخبرة في العمل على منصة .NET، صادفت العديد من المشاريع التي تستخدم مطابقة السلاسل. ورأيت أيضًا الصورة التالية: كان هناك حل مؤسسي واحد به العديد من المشاريع، حيث أجرى كل منها مقارنات سلسلة بشكل مختلف. ولكن ما الذي يجب استخدامه وكيفية توحيده؟ في كتاب CLR عبر C# من تأليف Richter، قرأت معلومات تفيد بأن طريقة ToUpperInvariant() أسرع من ToLowerInvariant().

مقتطف من الكتاب:

الأداء في .NET Core

بالطبع، لم أصدق ذلك وقررت إجراء بعض الاختبارات بعد ذلك على .NET Framework وكانت النتيجة صادمة لي - زيادة في الأداء بأكثر من 15%. وبعد ذلك، عند وصولي إلى العمل في صباح اليوم التالي، عرضت هذه القياسات على رؤسائي ومنحتهم إمكانية الوصول إلى كود المصدر. بعد ذلك، تم تغيير مشروعين من أصل 2 مشروعًا لاستيعاب القياسات الجديدة، وبالنظر إلى أن هذين المشروعين موجودان لمعالجة جداول Excel الضخمة، كانت النتيجة أكثر من مهمة بالنسبة للمنتج.

أقدم لكم أيضًا قياسات لإصدارات مختلفة من .NET Core، حتى يتمكن كل واحد منكم من الاختيار نحو الحل الأمثل. وأريد فقط أن أضيف أنه في الشركة التي أعمل فيها، نستخدم ToUpper() لمقارنة السلاسل.

رمز:

public const string defaultString =  "VXTDuob5YhummuDq1PPXOHE4PbrRjYfBjcHdFs8UcKSAHOCGievbUItWhU3ovCmRALgdZUG1CB0sQ4iMj8Z1ZfkML2owvfkOKxBCoFUAN4VLd4I8ietmlsS5PtdQEn6zEgy1uCVZXiXuubd0xM5ONVZBqDu6nOVq1GQloEjeRN8jXrj0MVUexB9aIECs7caKGddpuut3";

        [Benchmark]
        public bool ToLower()
        {
            return defaultString.ToLower() == defaultString.ToLower();
        }

        [Benchmark]
        public bool ToLowerInvariant()
        {
            return defaultString.ToLowerInvariant() == defaultString.ToLowerInvariant();
        }

        [Benchmark]
        public bool ToUpper()
        {
            return defaultString.ToUpper() == defaultString.ToUpper();
        }

        [Benchmark]
        public bool ToUpperInvariant()
        {
            return defaultString.ToUpperInvariant() == defaultString.ToUpperInvariant();
        }

الأداء في .NET Core

الأداء في .NET Core

في .NET Core 3.0، تكون الزيادة لكل من هذه الأساليب ~x2 وتقوم بموازنة التطبيقات فيما بينها.

الأداء في .NET Core

الأداء في .NET Core

تجميع الطبقة

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

مستوى .NET يصل

قم بترقية إصدار .NET Framework / .NET Core الخاص بك. في كثير من الأحيان، يوفر كل إصدار جديد مكاسب إضافية في الأداء ويضيف ميزات جديدة.

ولكن ما هي الفوائد بالضبط؟ دعونا نلقي نظرة على بعض منهم:

  • قدم .NET Core 3.0 صور R2R التي من شأنها تقليل وقت بدء تشغيل تطبيقات .NET Core.
  • مع الإصدار 2.2، ظهر تجميع المستوى، بفضل المبرمجين سيقضون وقتا أقل في إطلاق المشروع.
  • دعم معايير .NET الجديدة.
  • دعم لإصدار جديد من لغة البرمجة.
  • التحسين، مع كل إصدار جديد، يتم تحسين تحسين المكتبات الأساسية Collection/Struct/Stream/String/Regex وغير ذلك الكثير. إذا كنت تقوم بالترحيل من .NET Framework إلى .NET Core، فستحصل على تعزيز كبير في الأداء. على سبيل المثال، أرفق رابطًا لبعض التحسينات التي تمت إضافتها إلى .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

الأداء في .NET Core

اختتام

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

رابط إلى جيثب

المصدر: www.habr.com

إضافة تعليق