ประสิทธิภาพใน .NET Core

ประสิทธิภาพใน .NET Core

ประสิทธิภาพใน .NET Core

สวัสดีทุกคน! บทความนี้คือชุดแนวทางปฏิบัติที่ดีที่สุดที่เพื่อนร่วมงานและฉันใช้มานานเมื่อทำงานในโครงการต่างๆ

ข้อมูลเกี่ยวกับเครื่องจักรที่ทำการคำนวณ:เกณฑ์มาตรฐานDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 ลอจิคัล และ 4 ฟิสิคัลคอร์
.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 กับ ToArray และ Cycles


ฉันวางแผนที่จะเตรียมข้อมูลนี้ด้วยการเปิดตัว .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 นั้นเร็วกว่าเนื่องจากการเพิ่มประสิทธิภาพภายในและการจัดสรรขนาดคอลเลกชันที่ชัดเจน นอกจากนี้ โปรดจำไว้ว่าคอลเลกชันรายการมีข้อดีในตัวเอง และคุณควรใช้คอลเลกชันที่ถูกต้องโดยขึ้นอยู่กับการคำนวณที่จำเป็น แม้ว่าคุณจะเขียนตรรกะสำหรับการทำงานกับลูป อย่าลืมว่านี่เป็นลูปธรรมดาและอาจมีการปรับให้เหมาะสมสำหรับลูปที่เป็นไปได้ด้วย บทความถูกตีพิมพ์บน habr เมื่อนานมาแล้ว: https://habr.com/ru/post/124910/. ยังคงมีความเกี่ยวข้องและแนะนำให้อ่าน

โยน

ปีที่แล้ว ฉันทำงานในบริษัทแห่งหนึ่งในโครงการเดิม ซึ่งในโครงการนั้นเป็นเรื่องปกติที่จะประมวลผลการตรวจสอบภาคสนามผ่านโครงสร้างแบบ try-catch-throw ฉันเข้าใจแล้วว่านี่เป็นตรรกะทางธุรกิจที่ไม่ดีต่อสุขภาพสำหรับโปรเจ็กต์ ดังนั้นทุกครั้งที่เป็นไปได้ ฉันพยายามที่จะไม่ใช้การออกแบบดังกล่าว แต่ลองมาดูกันว่าทำไมแนวทางการจัดการข้อผิดพลาดกับโครงสร้างดังกล่าวจึงไม่ดี ฉันเขียนโค้ดเล็กๆ เพื่อเปรียบเทียบทั้งสองวิธีและทำการวัดประสิทธิภาพสำหรับแต่ละตัวเลือก

รหัส:

        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

Try catch ทำให้โค้ดเข้าใจยากขึ้น และเพิ่มเวลาดำเนินการของโปรแกรมของคุณ แต่ถ้าคุณต้องการโครงสร้างนี้ คุณไม่ควรแทรกบรรทัดโค้ดที่ไม่คาดว่าจะรองรับข้อผิดพลาด ซึ่งจะทำให้โค้ดเข้าใจได้ง่ายขึ้น ในความเป็นจริง มันไม่ได้จัดการข้อยกเว้นที่โหลดระบบมากนัก แต่เป็นการส่งข้อผิดพลาดด้วยตนเองผ่านโครงสร้าง Throw ใหม่

การโยนข้อยกเว้นช้ากว่าบางคลาสที่จะรวบรวมข้อผิดพลาดในรูปแบบที่ต้องการ หากคุณกำลังประมวลผลแบบฟอร์มหรือข้อมูลบางส่วน และคุณทราบอย่างชัดเจนว่าข้อผิดพลาดควรเป็นอย่างไร ทำไมไม่ดำเนินการประมวลผลล่ะ

คุณไม่ควรเขียนโครงสร้าง Throw new Exception() หากสถานการณ์นี้ไม่ได้ผิดปกติ การจัดการและการโยนข้อยกเว้นมีราคาแพงมาก!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

จากประสบการณ์ 5 ปีในการทำงานบนแพลตฟอร์ม .NET ฉันได้พบเห็นหลายโครงการที่ใช้การจับคู่สตริง ฉันยังเห็นภาพต่อไปนี้: มีโซลูชัน Enterprise หนึ่งโซลูชันที่มีหลายโปรเจ็กต์ ซึ่งแต่ละโซลูชันทำการเปรียบเทียบสตริงต่างกัน แต่ควรใช้อะไรและจะรวมเข้าด้วยกันได้อย่างไร? ในหนังสือ CLR ผ่าน C# โดย Richter ฉันอ่านข้อมูลที่ว่าวิธี ToUpperInvariant() นั้นเร็วกว่า ToLowerInvariant()

ข้อความที่ตัดตอนมาจากหนังสือ:

ประสิทธิภาพใน .NET Core

แน่นอนว่าฉันไม่เชื่อและตัดสินใจทำการทดสอบบางอย่างบน .NET Framework และผลลัพธ์ทำให้ฉันตกใจ - ประสิทธิภาพเพิ่มขึ้นมากกว่า 15% จากนั้น เมื่อมาถึงที่ทำงานในเช้าวันรุ่งขึ้น ฉันได้แสดงการวัดเหล่านี้ให้หัวหน้าของฉันดู และให้พวกเขาสามารถเข้าถึงซอร์สโค้ดได้ หลังจากนั้น 2 ใน 14 โปรเจ็กต์ก็มีการเปลี่ยนแปลงเพื่อรองรับการวัดใหม่ และเมื่อพิจารณาว่าทั้งสองโปรเจ็กต์นี้มีอยู่ในการประมวลผลตาราง 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 Tier Compilation ปรากฏขึ้น ต้องขอบคุณโปรแกรมเมอร์ที่จะใช้เวลาน้อยลงในการเปิดตัวโปรเจ็กต์
  • รองรับมาตรฐาน .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

ลิงก์ไปยัง GitHub

ที่มา: will.com

เพิ่มความคิดเห็น