.NET Core 中的效能

.NET Core 中的效能

.NET Core 中的效能

大家好! 本文是我和我的同事在處理不同專案時長期使用的最佳實踐的集合。

有關執行計算的機器的資訊:BenchmarkDotNet=v0.11.5,作業系統=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R),1 個 CPU,8 個邏輯核心和 4 個實體核心
.NET核心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 和循環


我本來打算在.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 中的效能

我們可以得出結論,由於其內部最佳化和明確集合大小分配,數組集合的迭代處理速度更快。 另外值得記住的是,List 集合有其自身的優點,您應該根據所需的計算使用正確的集合。 即使您編寫了使用循環的邏輯,也不要忘記這是一個普通的循環,並且它也可能受到循環最佳化的影響。 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 new Exception 構造拋出錯誤本身。

拋出異常比某些以所需格式收集錯誤的類別要慢。 如果您正在處理表單或某些數據,並且您清楚地知道錯誤應該是什麼,為什麼不處理它呢?

如果這種情況並非異常,則不應編寫 throw new Exception() 構造。 處理和拋出異常是非常昂貴的!

ToLower、ToLowerInvariant、ToUpper、ToUpperInvariant

在我 5 年的 .NET 平台工作經驗中,我遇到許多使用字串匹配的專案。 我還看到了下面的圖片:有一個企業解決方案有很多項目,每個項目執行字串比較的方式都不同。 但應該使用什麼以及如何統一呢? 在Richter的《CLR via C#》一書中,我讀到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

來源: www.habr.com

添加評論