<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          五個(gè) .NET 性能小貼士

          共 4779字,需瀏覽 10分鐘

           ·

          2021-12-25 02:23

          原文:bit.ly/3wSpO4o
          作者:Nikita Starichenko
          翻譯:精致碼農(nóng)

          大家好!今天我想和大家分享幾個(gè) .NET 的性能小貼士與基準(zhǔn)測(cè)試。

          我的系統(tǒng)環(huán)境:

          • BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19042.985

          • Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores

          • .NET SDK=5.0.104

          我將以百分比的形式提供基準(zhǔn)測(cè)試結(jié)果,其中 100% 是最快的結(jié)果。

          1用 StringBuilder 拼接字符串

          我們知道,字符串 string 是不可變的。因此,每當(dāng)你拼接字符串時(shí),就會(huì)分配一個(gè)新的字符串對(duì)象,并填充內(nèi)容,最終被回收。所有這些都有昂貴開(kāi)銷(xiāo),這就是為什么 StringBuilder 在字符串拼接時(shí)總有更好的性能。

          基準(zhǔn)測(cè)試?yán)樱?/p>

          private?static StringBuilder sb = new();

          [Benchmark]
          public?void?Concat3() => ExecuteConcat(3);
          [Benchmark]
          public?void?Concat5() => ExecuteConcat(5);
          [Benchmark]
          public?void?Concat10() => ExecuteConcat(10);
          [Benchmark]
          public?void?Concat100() => ExecuteConcat(100);
          [Benchmark]
          public?void?Concat1000() => ExecuteConcat(1000);

          [Benchmark]
          public?void?Builder3() => ExecuteBuilder(3);
          [Benchmark]
          public?void?Builder5() => ExecuteBuilder(5);
          [Benchmark]
          public?void?Builder10() => ExecuteBuilder(10);
          [Benchmark]
          public?void?Builder100() => ExecuteBuilder(100);
          [Benchmark]
          public?void?Builder1000() => ExecuteBuilder(1000);

          public?void?ExecuteConcat(int size)
          {
          string s = "";
          for (int i = 0; i < size; i++)
          {
          s += "a";
          }
          }

          public?void?ExecuteBuilder(int size)
          {
          sb.Clear();
          for (int i = 0; i < size; i++)
          {
          sb.Append("a");
          }
          }

          結(jié)果:

          1. 3 string concatenations - 218% (35.21 ns)
          2. 3 StringBuilder concatenations - 100% (16.09 ns)

          1. 5 string concatenations - 277% (66.99 ns)
          2. 5 StringBuilder concatenations - 100% (24.16 ns)

          1. 10 string concatenations - 379% (160.69 ns)
          2. 10 StringBuilder concatenations - 100% (42.37 ns)

          1. 100 string concatenations - 711% (2,796.63 ns)
          2. 100 StringBuilder concatenations - 100% (393.12 ns)

          1. 1000 string concatenations - 3800% (144,100.46 ns)
          2. 1000 StringBuilder concatenations - 100% (3,812.22 ns)

          2賦予動(dòng)態(tài)集合初始大小

          .NET 提供了很多集合類(lèi)型,比如 List, Dictionary, 和 HashSet。所有這些集合都有動(dòng)態(tài)的容量,當(dāng)你添加更多的項(xiàng)目時(shí),它們的大小會(huì)自動(dòng)擴(kuò)大。

          當(dāng)集合達(dá)到其大小限制時(shí),它將分配一個(gè)新的更大的內(nèi)存緩沖區(qū),這意味著要進(jìn)行額外的開(kāi)銷(xiāo)去分配容量。

          基準(zhǔn)測(cè)試?yán)樱?/p>

          [Benchmark]
          public?void?ListDynamicCapacity()
          {
          List<int> list = new List<int>();
          for (int i = 0; i < Size; i++)
          {
          list.Add(i);
          }
          }
          [Benchmark]
          public?void?ListPlannedCapacity()
          {
          List<int> list = new List<int>(Size);
          for (int i = 0; i < Size; i++)
          {
          list.Add(i);
          }
          }

          在第一個(gè)方法中,List 集合使用默認(rèn)容量初始化,并動(dòng)態(tài)擴(kuò)大。在第二個(gè)方法中,初始容量被設(shè)置為它所需要的固定大小。

          對(duì)于 1000 個(gè)項(xiàng)目,其結(jié)果是:

          1. List Dynamic Capacity - 140% (2.490 us)
          2. List Planned Capacity - 100% (1.774 us)

          DictionaryHashSet 的測(cè)試結(jié)果是:

          1. Dictionary Dynamic Capacity - 233% (20.314 us)
          2. Dictionary Planned Capacity - 100% (8.702 us)

          1. HashSet Dynamic Capacity - 223% (17.004 us)
          2. HashSet Planned Capacity - 100% (7.624 us)

          3ArrayPool 用于短時(shí)大數(shù)組

          數(shù)組的分配和回收的開(kāi)銷(xiāo)可能是相當(dāng)昂貴的,高頻地執(zhí)行這些分配會(huì)增加 GC 的壓力并損害性能。一個(gè)優(yōu)雅的解決方案使用是 System.Buffers.ArrayPool 類(lèi),它可以在 NuGet 的 Systems.Buffers 中找到。

          這個(gè)思想和 ThreadPool 很相似。為數(shù)組分配一個(gè)共享緩沖區(qū),你可以重復(fù)使用,而不需要實(shí)際分配和回收它們占用的內(nèi)存。基本用法是調(diào)用 ArrayPool.Shared.Rent(size),這將返回一個(gè)常規(guī)數(shù)組,你可以以任何方式使用它。完成后,調(diào)用 ArrayPool.Shared.Return(array) 將緩沖區(qū)返回到共享池中。

          基準(zhǔn)測(cè)試?yán)樱?/p>

          [Benchmark]
          public?void?RegularArray()
          {
          int[] array = new?int[ArraySize];
          }
          [Benchmark]
          public?void?SharedArrayPool()
          {
          var pool = ArrayPool<int>.Shared;
          int[] array = pool.Rent(ArraySize);
          pool.Return(array);
          }

          ArraySize = 1000 的結(jié)果:

          1. Regular Array - 2270% (440.41 ns)
          2. Shared ArrayPool - 100% (19.40 ns)

          4結(jié)構(gòu)代替類(lèi)

          當(dāng)涉及到對(duì)象回收時(shí),Struct 有如下幾個(gè)好處:

          • 當(dāng)結(jié)構(gòu)類(lèi)型不是類(lèi)的一部分時(shí),它們被分配在堆棧中,根本不需要垃圾回收。

          • 當(dāng)結(jié)構(gòu)是類(lèi)(或任何引用類(lèi)型)的一部分時(shí),它們被存儲(chǔ)在堆中。在這種情況下,它們是內(nèi)聯(lián)存儲(chǔ)的,并且會(huì)隨包含類(lèi)型回收而回收。內(nèi)聯(lián)意味著該結(jié)構(gòu)的數(shù)據(jù)是按原樣存儲(chǔ)的,這與引用類(lèi)型相反,在引用類(lèi)型中,指針被存儲(chǔ)到堆上另一個(gè)位置。所以回收的成本要低很多。

          • 結(jié)構(gòu)比引用類(lèi)型占用的內(nèi)存更少,因?yàn)樗鼈儧](méi)有 ObjectHeaderMethodTable

          基準(zhǔn)測(cè)試?yán)樱?/p>

          class?VectorClass
          {
          public?int X { get; set; }
          public?int Y { get; set; }
          }

          struct VectorStruct
          {
          public?int X { get; set; }
          public?int Y { get; set; }
          }

          private?const?int ITEMS = 10000;


          [Benchmark]
          public?void?WithClass()
          {
          VectorClass[] vectors = new VectorClass[ITEMS];
          for (int i = 0; i < ITEMS; i++)
          {
          vectors[i] = new VectorClass();
          vectors[i].X = 5;
          vectors[i].Y = 10;
          }
          }

          [Benchmark]
          public?void?WithStruct()
          {
          VectorStruct[] vectors = new VectorStruct[ITEMS];
          // At this point all the vectors instances are already allocated with default values
          for (int i = 0; i < ITEMS; i++)
          {
          vectors[i].X = 5;
          vectors[i].Y = 10;
          }
          }

          結(jié)果:

          1. With Class - 742% (88.83 us)
          2. With Struct - 100% (11.97 us)

          5ConcurrentQueue 代替 ConcurrentBag

          在沒(méi)有基準(zhǔn)測(cè)試的情況下,不要使用 ConcurrentBag。這個(gè)集合是為非常特殊的使用場(chǎng)景而設(shè)計(jì)的(當(dāng)經(jīng)常有項(xiàng)目被排隊(duì)的線程刪除時(shí))。如果需要一個(gè)并發(fā)的集合隊(duì)列,請(qǐng)選擇 ConcurrentQueue

          基準(zhǔn)測(cè)試?yán)樱?/p>

          private?static?int Size = 1000;

          [Benchmark]
          public?void?Bag()
          {
          ConcurrentBag<int> bag = new();
          for (int i = 0; i < Size; i++)
          {
          bag.Add(i);
          }
          }

          [Benchmark]
          public?void?Queue()
          {
          ConcurrentQueue<int> bag = new();
          for (int i = 0; i < Size; i++)
          {
          bag.Enqueue(i);
          }
          }

          結(jié)果:

          1. ConcurrentBag - 165% (24.21 us)
          2. ConcurrentQueue - 100% (14.64 us)

          感謝大家閱讀!


          瀏覽 27
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久久久亚洲AV无码网影音先锋 | 色老板成人永久免费视频 | 艹逼欧美变态 | 日韩电影精品 | 日韩免费黄色视频 |