使用 BenchmarkDotNet 比較指定容量的 List 的效能

Newbe36524發表於2022-12-19

我們之前提到 List 是 .NET 中常用的資料結構,其在儲存大量資料時,如果能夠指定它的初始化容量,就會有效能提升。這個最佳化的方法並不是很明顯,因此本文將使用 BenchmarkDotNet 庫,透過定量對比的方式來證明這一點。

實驗過程

引入 BenchmarkDotNet

首先,我們需要在專案中引入 BenchmarkDotNet 庫。這可以透過在專案的 NuGet 包管理器中搜尋並安裝 BenchmarkDotNet 來實現。

指定需要測試的方法和引數

接下來,我們需要指定需要測試的方法和引數。這可以透過在程式碼中使用 [Benchmark] 屬性來實現。例如,我們可以在測試類中定義兩個測試方法,一個使用指定容量的 List,一個使用未指定容量的 List。

public class ListBenchmark
{
    [Benchmark]
    public void ListWithCapacity()
    {
        var list = new List<int>(1000000);
        for (int i = 0; i < 1000000; i++)
        {
            list.Add(i);
        }
    }

    [Benchmark]
    public void ListWithoutCapacity()
    {
        var list = new List<int>();
        for (int i = 0; i < 1000000; i++)
        {
            list.Add(i);
        }
    }
}

我們還可以使用其他引數來指定測試的一些細節,如使用的 .NET 框架版本,是否進行記憶體測量等。

[SimpleJob(RuntimeMoniker.Net70)]
[SimpleJob(RuntimeMoniker.NetCoreApp31)]
[MemoryDiagnoser]
public class ListBenchmark
{
    [Benchmark]
    public void ListWithCapacity()
    {
        var list = new List<int>(1000000);
        for (int i = 0; i < 1000000; i++)
        {
            list.Add(i);
        }
    }

    [Benchmark]
    public void ListWithoutCapacity()
    {
        var list = new List<int>();
        for (int i = 0; i < 1000000; i++)
        {
            list.Add(i);
        }
    }
}

執行測試

最後,我們可以使用 BenchmarkRunner 類來執行測試。這可以透過在 Main 方法中呼叫 BenchmarkRunner.Run<T>() 方法來實現。其中 T 是包含測試方法的類的型別。

class Program
{
    static void Main(string[] args)
    {
        BenchmarkRunner.Run<ListBenchmark>();
    }
}

實驗結果

執行測試後,我們可以得到若干個指標的測試結果。這些指標可能包括執行時間、記憶體使用量等。透過對比這些指標,我們可以得出結論:使用指定容量的 List 效能優於未指定容量的 List。

例如,我們可以看到,使用指定容量的 List 的平均執行時間要比未指定容量的 List 少得多,記憶體使用量也更少。

// * Summary *

BenchmarkDotNet=v0.13.2, OS=Windows 11 (10.0.22000.1335/21H2)
12th Gen Intel Core i7-12700, 1 CPU, 20 logical and 12 physical cores
.NET SDK=7.0.101
[Host]        : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2
.NET 7.0      : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2
.NET Core 3.1 : .NET Core 3.1.32 (CoreCLR 4.700.22.55902, CoreFX 4.700.22.56512), X64 RyuJIT AVX2


|              Method |           Job |       Runtime |     Mean |     Error |    StdDev |     Gen0 |     Gen1 |     Gen2 | Allocated |
|-------------------- |-------------- |-------------- |---------:|----------:|----------:|---------:|---------:|---------:|----------:|
|    ListWithCapacity |      .NET 7.0 |      .NET 7.0 | 1.392 ms | 0.0302 ms | 0.0891 ms | 164.0625 | 164.0625 | 164.0625 |   3.81 MB |
| ListWithoutCapacity |      .NET 7.0 |      .NET 7.0 | 2.602 ms | 0.0503 ms | 0.0559 ms | 507.8125 | 500.0000 | 500.0000 |      8 MB |
|    ListWithCapacity | .NET Core 3.1 | .NET Core 3.1 | 1.168 ms | 0.0227 ms | 0.0278 ms | 218.7500 | 218.7500 | 218.7500 |   3.81 MB |
| ListWithoutCapacity | .NET Core 3.1 | .NET Core 3.1 | 2.652 ms | 0.0520 ms | 0.0461 ms | 507.8125 | 500.0000 | 500.0000 |      8 MB |

  

總結

本文透過 BenchmarkDotNet 庫,使用定量對比的方式,證明了使用指定容量的 List 效能優於未指定容量的 List。這是因為指定容量的 List 在初始化時,會為其分配指定大小的記憶體空間,而未指定容量的 List 則會在新增元素時,根據需要動態分配記憶體空間。因此,使用指定容量的 List 可以減少記憶體分配的次數,從而提升效能。

參考資料

  • BenchmarkDotNet[1]

本文采用 Chat OpenAI 輔助注水澆築而成,如有雷同,完全有可能。

  • 本文作者: newbe36524
  • 本文連結: https://www.newbe.pro/ChatAI/How-to-use-benchmark-to-compare-performance-about-list-with-capacity-specified/
  • 版權宣告: 本部落格所有文章除特別宣告外,均採用 BY-NC-SA 許可協議。轉載請註明出處!

參考資料

[1]

BenchmarkDotNet: https://benchmarkdotnet.org/

相關文章