Kinerja dalam .NET Core

Halo semuanya! Artikel ini adalah kumpulan Praktik-Praktik Terbaik, yang telah lama saya dan rekan saya gunakan ketika mengerjakan proyek yang berbeda.
Informasi tentang mesin tempat perhitungan dilakukan:BenchmarkDotNet = v0.11.5, OS = Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 core logis dan 4 fisik
.NET Core SDK = 3.0.100
[Host]: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
Core: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
[Host]: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT
Core: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT
Pekerjaan = Core Runtime = Core
ToList vs ToArray dan Cycles
Saya berencana untuk menyiapkan informasi ini dengan rilis .NET Core 3.0, tetapi mereka mendahului saya, saya tidak ingin mencuri ketenaran orang lain dan menyalin informasi orang lain, jadi saya hanya akan menunjukkan
tautan ke artikel bagus di mana perbandingannya dirinci .
Dari diri saya sendiri, saya hanya ingin menunjukkan kepada Anda pengukuran dan hasil saya, saya menambahkan loop terbalik kepada mereka untuk penggemar "gaya C ++" dari loop penulisan.
Kode: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; } }
Kinerja dalam .NET Core 2.2 dan 3.0 hampir identik. Inilah yang saya berhasil dapatkan. NET Core 3.0:


Kita dapat menyimpulkan bahwa pemrosesan loop dari koleksi tipe Array lebih cepat, karena optimasi internal dan alokasi eksplisit dari ukuran koleksi. Perlu juga diingat bahwa koleksi Daftar jenis memiliki kelebihan dan Anda harus menggunakan koleksi yang diinginkan tergantung pada perhitungan yang diperlukan. Sekalipun Anda menulis logika bekerja dengan siklus, jangan lupa bahwa ini adalah loop biasa dan itu juga tunduk pada kemungkinan optimalisasi siklus. Sebuah artikel muncul di habr untuk waktu yang lama:
https://habr.com/en/post/124910/ . Masih relevan dan direkomendasikan untuk dibaca.
Lempar
Setahun yang lalu, saya bekerja di sebuah perusahaan di proyek legacy, dalam proyek itu dalam lingkup normal untuk menangani validasi lapangan melalui konstruksi coba-coba-lempar. Saya sudah mengerti bahwa ini adalah logika bisnis yang tidak sehat dari proyek ini, jadi saya mencoba untuk tidak menggunakan desain seperti itu jika memungkinkan. Tapi mari kita lihat apa pendekatan buruk untuk menangani kesalahan dengan desain seperti itu. Saya menulis kode kecil untuk membandingkan dua pendekatan dan menembak "bangku" untuk setiap opsi.
Kode: 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; }
Hasil dalam .NET Core 3.0 dan Core 2.2 memiliki hasil yang serupa (.NET Core 3.0):


Coba tangkap mempersulit pemahaman kode dan meningkatkan waktu eksekusi program Anda. Tetapi jika Anda membutuhkan konstruksi ini, Anda sebaiknya tidak memasukkan baris kode yang tidak diharapkan penanganan kesalahan - ini akan memudahkan pemahaman kode. Bahkan, tidak banyak penanganan pengecualian yang memuat sistem sebagai melempar kesalahan sendiri melalui lemparan konstruksi Pengecualian baru.
Pengecualian melempar lebih lambat dari kelas mana pun yang mengumpulkan kesalahan dalam format yang diinginkan. Jika Anda memproses formulir atau data apa pun dan jelas tahu kesalahan apa yang seharusnya terjadi, mengapa tidak memprosesnya?
Anda tidak boleh menulis throw Exception baru () jika situasi ini tidak luar biasa.
Menangani dan melempar pengecualian sangat mahal !!!ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant
Selama 5 tahun pengalamannya di platform .NET, ia telah bertemu banyak proyek yang menggunakan pencocokan string. Saya juga melihat gambar berikut: ada satu solusi Enterprise dengan banyak proyek, yang masing-masing melakukan perbandingan string dengan cara yang berbeda. Tetapi apa yang layak digunakan dan bagaimana menyatukannya? Di Richter's CLR via C #, saya membaca bahwa ToUpperInvariant () lebih cepat daripada ToLowerInvariant ().
Kliping dari buku:

Tentu saja, saya tidak percaya dan memutuskan untuk melakukan beberapa tes saat itu pada .NET Framework dan hasilnya mengejutkan saya - peningkatan kinerja lebih dari 15%. Lebih jauh pada saat kedatangan untuk bekerja keesokan paginya saya menunjukkan pengukuran ini kepada atasan saya dan memberi mereka akses ke sumbernya. Setelah itu, 2 dari 14 proyek diubah untuk pengukuran baru, dan mengingat bahwa kedua proyek ini ada untuk memproses tabel excel besar, hasilnya lebih dari signifikan untuk produk.
Saya juga menyajikan kepada Anda pengukuran untuk berbagai versi .NET Core, sehingga Anda masing-masing dapat membuat pilihan ke arah solusi yang paling optimal. Dan saya hanya ingin menambahkan itu di perusahaan tempat saya bekerja, kami menggunakan ToUpper () untuk membandingkan string.
Kode: 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(); }
; 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(); }


Di .NET Core 3.0, keuntungan untuk masing-masing metode ini adalah ~ x2 dan menyeimbangkan implementasi di antara mereka sendiri.


Kompilasi tingkat
Dalam artikel terakhir saya, saya menjelaskan secara singkat fungsi ini, saya ingin memperbaiki dan menambah kata-kata saya. Kompilasi multilevel mempercepat waktu peluncuran solusi Anda, tetapi Anda mengorbankan bahwa bagian-bagian kode Anda akan dikompilasi menjadi versi yang lebih optimal di latar belakang, yang dapat menyebabkan overhead kecil. Dengan munculnya NET Core 3.0, waktu pembangunan proyek dengan kompilasi tingkat memungkinkan penurunan dan perbaikan bug yang terkait dengan teknologi ini. Sebelumnya, teknologi ini menyebabkan kesalahan dalam permintaan pertama di ASP.NET Core dan membeku selama pembangunan pertama dalam mode kompilasi bertingkat. Saat ini, ini diaktifkan secara default di .NET Core 3.0, tetapi Anda dapat menonaktifkannya sesuai keinginan. Jika Anda berada di posisi pimpinan tim, senior, menengah atau Anda adalah kepala departemen, Anda harus memahami bahwa perkembangan cepat proyek meningkatkan nilai tim dan teknologi ini akan memungkinkan Anda menghemat waktu pengembang dan waktu proyek.
.NET naik level
Tingkatkan .NET Framework / .NET Core Anda. Seringkali, setiap versi baru memberikan peningkatan kinerja tambahan dan menambahkan fitur baru.
Tapi apa sebenarnya manfaatnya? Mari kita lihat beberapa di antaranya:
- Dalam .NET Core 3.0, gambar R2R telah diperkenalkan yang akan mengurangi waktu startup aplikasi .NET Core.
- Versi 2.2 memperkenalkan Kompilasi Tingkat, berkat programer mana yang akan menghabiskan lebih sedikit waktu untuk meluncurkan proyek.
- Dukungan untuk .NET Standard baru.
- Dukungan untuk versi baru bahasa pemrograman.
- Optimasi, dengan setiap versi baru, optimisasi ditingkatkan oleh pustaka dasar Koleksi / Struct / Stream / String / Regex dan banyak lagi. Jika Anda memutakhirkan dari .NET Framework ke .NET Core, Anda akan mendapatkan peningkatan kinerja besar di luar kotak. Misalnya, saya melampirkan tautan ke bagian optimasi yang ditambahkan di .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

Kesimpulan
Saat menulis kode, Anda harus memperhatikan berbagai aspek proyek Anda dan menggunakan fungsi bahasa dan platform pemrograman Anda untuk mencapai hasil terbaik. Saya akan senang jika Anda membagikan pengetahuan Anda terkait dengan optimasi di .NET.
Tautan Github