Prestasi dalam .NET Core

Prestasi dalam .NET Core

Prestasi dalam .NET Core

Hai semua! Artikel ini ialah koleksi Amalan Terbaik yang telah lama saya dan rakan sekerja saya gunakan semasa mengerjakan projek yang berbeza.

Maklumat tentang mesin di mana pengiraan dilakukan:BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logik dan 4 teras fizikal
.SDK Teras BERSIH=3.0.100
[Hos]: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
Teras: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
[Hos]: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT
Teras: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT

Kerja=Masa Jalan Teras=Teras

ToList vs ToArray dan Cycles


Saya bercadang untuk menyediakan maklumat ini dengan keluaran .NET Core 3.0, tetapi mereka mengalahkan saya, saya tidak mahu mencuri kemuliaan orang lain dan menyalin maklumat orang lain, jadi saya hanya akan menunjukkan pautan ke artikel yang bagus di mana perbandingan diterangkan secara terperinci.

Bagi pihak saya sendiri, saya hanya ingin membentangkan kepada anda ukuran dan hasil saya; Saya menambah gelung terbalik kepada mereka untuk pencinta "gaya C++" gelung penulisan.

Kod:

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;
        }
    }

Kelajuan prestasi dalam .NET Core 2.2 dan 3.0 adalah hampir sama. Inilah yang saya dapat dalam .NET Core 3.0:

Prestasi dalam .NET Core

Prestasi dalam .NET Core

Kita boleh membuat kesimpulan bahawa pemprosesan berulang bagi koleksi Array adalah lebih pantas disebabkan pengoptimuman dalaman dan peruntukan saiz koleksi yang jelas. Perlu diingat juga bahawa koleksi Senarai mempunyai kelebihan tersendiri dan anda harus menggunakan koleksi yang betul bergantung pada pengiraan yang diperlukan. Walaupun anda menulis logik untuk bekerja dengan gelung, jangan lupa bahawa ini adalah gelung biasa dan ia juga tertakluk kepada pengoptimuman gelung yang mungkin. Satu artikel telah diterbitkan pada habr agak lama dahulu: https://habr.com/ru/post/124910/. Ia masih relevan dan disyorkan untuk dibaca.

Baling

Setahun yang lalu, saya bekerja di sebuah syarikat dalam projek warisan, dalam projek itu adalah perkara biasa untuk memproses pengesahan medan melalui binaan cuba-tangkap-lempar. Saya sudah faham bahawa ini adalah logik perniagaan yang tidak sihat untuk projek itu, jadi apabila mungkin saya cuba untuk tidak menggunakan reka bentuk sedemikian. Tetapi mari kita fikirkan mengapa pendekatan untuk mengendalikan ralat dengan pembinaan sedemikian adalah buruk. Saya menulis kod kecil untuk membandingkan kedua-dua pendekatan dan membuat penanda aras untuk setiap pilihan.

Kod:

        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;
        }

Keputusan dalam .NET Core 3.0 dan Core 2.2 mempunyai hasil yang serupa (.NET Core 3.0):

Prestasi dalam .NET Core

Prestasi dalam .NET Core

Cuba tangkap menjadikan kod lebih sukar untuk difahami dan meningkatkan masa pelaksanaan program anda. Tetapi jika anda memerlukan pembinaan ini, anda tidak seharusnya memasukkan baris kod tersebut yang tidak dijangka mengendalikan ralat - ini akan menjadikan kod lebih mudah difahami. Sebenarnya, bukan hanya pengendalian pengecualian yang memuatkan sistem, sebaliknya melontarkan ralat itu sendiri melalui binaan Pengecualian baharu lontaran.

Pengecualian melontar adalah lebih perlahan daripada beberapa kelas yang akan mengumpulkan ralat dalam format yang diperlukan. Jika anda sedang memproses borang atau beberapa data dan anda tahu dengan jelas apakah ralat itu, mengapa tidak memprosesnya?

Anda tidak sepatutnya menulis binaan Exception() lontaran baru jika keadaan ini tidak luar biasa. Mengendalikan dan membuang pengecualian adalah sangat mahal!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

Sepanjang 5 tahun pengalaman saya bekerja pada platform .NET, saya telah menemui banyak projek yang menggunakan padanan rentetan. Saya juga melihat gambar berikut: terdapat satu penyelesaian Perusahaan dengan banyak projek, setiap satunya melakukan perbandingan rentetan secara berbeza. Tetapi apa yang harus digunakan dan bagaimana untuk menyatukannya? Dalam buku CLR melalui C# oleh Richter, saya membaca maklumat bahawa kaedah ToUpperInvariant() adalah lebih pantas daripada ToLowerInvariant().

Petikan dari buku:

Prestasi dalam .NET Core

Sudah tentu, saya tidak mempercayainya dan memutuskan untuk menjalankan beberapa ujian pada Rangka Kerja .NET dan hasilnya mengejutkan saya - peningkatan prestasi lebih daripada 15%. Kemudian, apabila tiba di tempat kerja keesokan harinya, saya menunjukkan ukuran ini kepada atasan saya dan memberi mereka akses kepada kod sumber. Selepas ini, 2 daripada 14 projek telah ditukar untuk menampung ukuran baharu, dan memandangkan kedua-dua projek ini wujud untuk memproses jadual Excel yang besar, hasilnya adalah lebih penting untuk produk.

Saya juga membentangkan kepada anda ukuran untuk versi .NET Core yang berbeza, supaya setiap daripada anda boleh membuat pilihan ke arah penyelesaian yang paling optimum. Dan saya hanya ingin menambah bahawa dalam syarikat tempat saya bekerja, kami menggunakan ToUpper() untuk membandingkan rentetan.

Kod:

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();
        }

Prestasi dalam .NET Core

Prestasi dalam .NET Core

Dalam .NET Core 3.0, peningkatan bagi setiap kaedah ini ialah ~x2 dan mengimbangi pelaksanaan antara mereka sendiri.

Prestasi dalam .NET Core

Prestasi dalam .NET Core

Penyusunan Peringkat

Dalam artikel terakhir saya, saya menerangkan fungsi ini secara ringkas, saya ingin membetulkan dan menambah kata-kata saya. Kompilasi berbilang peringkat mempercepatkan masa permulaan penyelesaian anda, tetapi anda mengorbankan bahagian kod anda akan disusun menjadi versi yang lebih dioptimumkan di latar belakang, yang boleh memperkenalkan overhed kecil. Dengan kemunculan NET Core 3.0, masa binaan untuk projek dengan kompilasi peringkat didayakan telah berkurangan dan pepijat yang berkaitan dengan teknologi ini telah diperbaiki. Sebelum ini, teknologi ini membawa kepada ralat dalam permintaan pertama dalam ASP.NET Core dan membeku semasa binaan pertama dalam mod kompilasi berbilang peringkat. Ia kini didayakan secara lalai dalam .NET Core 3.0, tetapi anda boleh melumpuhkannya jika anda mahu. Jika anda berada dalam kedudukan ketua pasukan, kanan, pertengahan atau anda ketua jabatan, maka anda mesti faham bahawa pembangunan projek yang pesat meningkatkan nilai pasukan dan teknologi ini akan membolehkan anda menjimatkan masa untuk kedua-dua pembangun dan masa projek itu sendiri.

.BERSIH naik tahap

Tingkatkan versi .NET Framework / .NET Core anda. Selalunya, setiap versi baharu memberikan peningkatan prestasi tambahan dan menambah ciri baharu.

Tetapi apa sebenarnya faedahnya? Mari lihat beberapa daripada mereka:

  • .NET Core 3.0 memperkenalkan imej R2R yang akan mengurangkan masa permulaan aplikasi .NET Core.
  • Dengan versi 2.2, Tier Compilation muncul, terima kasih kepada pengaturcara yang akan menghabiskan lebih sedikit masa untuk melancarkan projek.
  • Sokongan untuk Piawaian .NET baharu.
  • Sokongan untuk versi baharu bahasa pengaturcaraan.
  • Pengoptimuman, dengan setiap versi baharu, pengoptimuman perpustakaan asas Collection/Struct/Stream/String/Regex dan banyak lagi bertambah baik. Jika anda berhijrah daripada Rangka Kerja .NET ke Teras .NET, anda akan mendapat peningkatan prestasi yang besar di luar kotak. Sebagai contoh, saya melampirkan pautan kepada beberapa pengoptimuman yang telah ditambahkan pada .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

Prestasi dalam .NET Core

Kesimpulan

Semasa menulis kod, adalah wajar memberi perhatian kepada aspek yang berbeza dalam projek anda dan menggunakan ciri bahasa pengaturcaraan dan platform anda untuk mencapai hasil yang terbaik. Saya gembira jika anda berkongsi pengetahuan anda berkaitan pengoptimuman dalam .NET.

Pautan ke github

Sumber: www.habr.com

Tambah komen