使用 BenchmarkDotNet 比较指定容量的 List 的性能
我们之前提到 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/
使用 BenchmarkDotNet 比较指定容量的 List 的性能的更多相关文章
- 为什么要指定HashMap的容量?HashMap指定容量初始化后,底层Hash数组已经被分配内存了吗?
为什么要指定HashMap的容量? 首先创建HashMap时,指定容量比如1024后,并不是HashMap的size不是1024,而是0,插入多少元素,size就是多少: 然后如果不指定HashMap ...
- Docker 指定容量
vim /etc/sysconfig/docker-storage加入以下命令 DOCKER_STORAGE_OPTIONS="--storage-driver devicemapper - ...
- Java:String、StringBuffer和StringBuilder的区别
1 String String:字符串常量,字符串长度不可变.Java中String是immutable(不可变)的. String类的包含如下定义: /** The value is used fo ...
- Java的String、StringBuffer和StringBuilder的区别
1.String 2.Stringbuffer 3.StringBuilder 4.三者之间的区别 5.使用策略 1.String public final class String implemen ...
- String、StringBuffer和StringBuilder的区别
1 String String:字符串常量,字符串长度不可变.Java中String是immutable(不可变)的. String类的包含如下定义: /** The value is used fo ...
- String, StringBuilder, StringBuffer问题
1. 区别 String为字符串常量,而StringBuilder和StringBuffer都是字符串变量,其中StringBuilder线程非安全,StringBuffer线程安全. 每次对 Str ...
- 重温java中的String,StringBuffer,StringBuilder类
不论什么一个系统在开发的过程中, 相信都不会缺少对字符串的处理. 在 java 语言中, 用来处理字符串的的类经常使用的有 3 个: String.StringBuffer.StringBuilder ...
- String、StringBuffer、StringBuilder区分和性能比较
转载自:http://www.cnblogs.com/fancydeepin/archive/2013/04/23/min-snail-speak_String-StringBuffer-String ...
- Java中的String、StringBuffer和StringBuilder的区别
类型 是否可变 线程安全 能否频繁修改 String 不可变 安全 否 StringBuffer 可变 安全 能 StringBuilder 可变 不安全 能 1.可变与 ...
- [Java]String、 StringBuffer、StringBuilder的区别
一.异同点: 1) 都是 final 类, 都不允许被继承; 2) String 长度是不可变的, StringBuffer.StringBuilder 长度是可变的; 3) StringBuffer ...
随机推荐
- 源码学习之MyBatis的底层查询原理
导读 本文通过MyBatis一个低版本的bug(3.4.5之前的版本)入手,分析MyBatis的一次完整的查询流程,从配置文件的解析到一个查询的完整执行过程详细解读MyBatis的一次查询流程,通过本 ...
- numpy中的一些常用的关键字用法
1.np.full() 原型:numpy.full(shape, fill_value, dtype=None, order='C') eg: 2.np.flatten():该函数返回一个折叠成一维的 ...
- [Android开发学iOS系列] iOS写UI的几种方式
[Android开发学iOS系列] iOS写UI的几种方式 作为一个现代化的平台, iOS的发展也经历了好几个时代. 本文讲讲iOS写UI的几种主要方式和各自的特点. iOS写UI的方式 在iOS中写 ...
- 它让你1小时精通RabbitMQ消息队列(新增死信处理)
支持.NET/.NET Framework/.NET Core RabbitMQ作为一款主流的消息队列工具早已广受欢迎.相比于其它的MQ工具,RabbitMQ支持的语言更多.功能更完善. 本文提供一种 ...
- 走进shell
走进shell 在Linux早起,还没有出现图形化,超哥和其他系统管理员都只能坐在电脑前,输入shell命令,查看控制台的文本输出. 在大多数Linux发行版里,例如centos,可以简单的用组合键来 ...
- Mysql入门练习题
1.在students表中,查询年龄大于25岁,且为男性的同学的名字和年龄 mysql> select name,age from students where age>25 and ge ...
- 前后端分离项目(十):实现"改"功能(前后端)
好家伙,本篇介绍如何实现"改" 我们先来看看效果吧 (这可不是假数据哟,这是真数据哟) (忘记录鼠标了,这里是点了一下刷新) First Of All 我们依旧先来理一下思路: ...
- 在ubuntu 上安装golang
https://golang.google.cn/dl/ 方式一 下载安装包 wget https://golang.google.cn/dl/go1.19.linux-amd64.tar.gz 解压 ...
- 第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南)-L Bit Sequence
题意 给你两个数l,m,大小为m的数组a,求[0,l]之间满足以下条件的数x的个数: 对于任何i输入[0,m-1],f(x+i)%2=a[i]:f(k):代表k在二进制下1的个数 m的范围<=1 ...
- ARM TrustZone白皮书部分阅读
嵌入式系统安全的一些解决方法及缺陷 外部硬件安全模块:在主SoC之外包含一个专用的硬件安全模块或可信元件,e.g. 手机的SIM卡.隔离仅限于可以从非易失性存储器运行的相对静态程序 内部硬件安全模块: ...