.NET性能系列文章一:.NET7的性能改进

这些方法在.NET7 中变得更快

80fc1b7c6fe7599f68ae0f56123a1b9e.jpeg

照片来自 CHUTTERSNAP[1] 的 Unsplash[2]

欢迎阅读.NET 性能系列的第一章。这一系列的特点是对.NET 世界中许多不同的主题进行研究、比较性能。正如标题所说的那样,本章节在于.NET7 中的性能改进。你将看到哪种方法是实现特定功能最快的方法,以及大量的技巧和敲门,如何付出较小的代价就能最大化你代码性能。如果你对这些主题感兴趣,那请您继续关注。

.NET 7 目前(17.10.2022)处于预览阶段,将于 2022 年 11 月发布。通过这个新版本,微软提供了一些大的性能改进。这篇 .NET 性能系列的第一篇文章,是关于从.NET6 到.NET7 最值得注意的性能改进。

LINQ

最相关的改进肯定是在 LINQ 中,在.NET 7 中dotnet 社区[3]利用 LINQ 中对数字数组的处理来使用Vector<T>(SIMD)。这大大改善了一些 LINQ 方法性能,你可以在List<int>int[]以及其他数字集合上调用。现在 LINQ 方法也能直接访问底层数组,而不是使用枚举器访问。让我们来看看这些方法相对于.NET 6 是如何表现的。

我使用BenchmarkDotNet[4]来比较.NET6 和.NET7 相同代码的性能。

1. Min 和 Max 方法

首先是 LINQ 方法Min()Max()。它们被用来识别数字枚举中的最低值或最高值。新的实现特别要求有一个先前枚举的集合作为源,因此我们必须在这个基准测试中创建一个数组。

[Params(1000)]
public int Length { get; set; }private int[] arr;[GlobalSetup]
public void GlobalSetup() => arr = Enumerable.Range(0, Length).ToArray();[Benchmark]
public int Min() => arr.Min();[Benchmark]
public int Max() => arr.Max();

在.NET 6 和.NET 7 上执行这些基准,在我的机器上会得出以下结果。

方法运行时数组长度平均值比率分配
Minoutside_default.png10003,494.08 ns53.2432 B
Minoutside_default.png100065.64 ns1.00-






Maxoutside_default.png10003,025.41 ns45.9232 B
Maxoutside_default.png100065.93 ns1.00-
223acd6a37d0ee8c5da61482716b87a1.png

这里非常突出的是新的.NET7 所展示的性能改进有多大。我们可以看到与.NET 6 相比,改进幅度超过 4500%。这不仅是因为在内部实现中使用了另一种类型,而且还因为不再发生额外的堆内存分配。

2. Average 和 Sum

另一个很大的改进是Average()Sum()方法。当处理大的double集合时,这些性能优化能展现出更好的结果,这就是为什么我们要用一个double[]来测试它们。

[Params(1000)]
public int Length { get; set; }private double[] arr;[GlobalSetup]
public void GlobalSetup()
{var random = new Random();arr = Enumerable.Range(0, Length).Select(_ => random.NextDouble()).ToArray();
}[Benchmark]
public double Average() => arr.Average();[Benchmark]
public double Sum() => arr.Sum();

结果显示,性能显著提高了 500%以上,而且同样没有了内存分配!

方法运行时数组长度平均值比率分配
Averageoutside_default.png10003,438.0 ns5.5032 B
Averageoutside_default.png1000630.3 ns1.00-






Sumoutside_default.png10003,303.8 ns5.2532 B
Sumoutside_default.png1000629.3 ns1.00-
f9c93b4c71314c7872e38461dc8006d4.png

这里的性能提升并不像前面的例子那么突出,但还是非常高的!

3. Order

接下来是这是新增了两个排序方法Order()OrderDescending()。当你不想映射到IComparable类型时,应该使用新的方法取代.NET7 中旧的OrderBy()OrderByDescending()方法。

[Params(1000)]
public int Length { get; set; }private double[] arr;[GlobalSetup]
public void GlobalSetup()
{var random = new Random();arr = Enumerable.Range(0, Length).Select(_ => random.NextDouble()).ToArray();
}[Benchmark]
public double[] OrderBy() => arr.OrderBy(d => d).ToArray();#if NET7_0
[Benchmark]
public double[] Order() => arr.Order().ToArray();
#endif
方法数组长度平均值风波无
OrderBy100051.13 μs27.61 KB
Order100050.82 μs19.77 KB

在这个基准中,只使用了.NET 7,因为Order()方法在旧的运行时中不可用。

我们无法看到这两种方法之间的性能影响。然而,我们可以看到的是在堆内存分配方面有很大的改进,这将显著减少垃圾收集,从而节省一些 GC 时间。

System.IO

在.NET 7 中,Windows 下的 IO 性能有了些许改善。WriteAllText()方法不再使用那么多分配的内存,ReadAllText()方法与.NET 6 相比也快了一些。

[Benchmark]
public void WriteAllText() => File.WriteAllText(path1, content);[Benchmark]
public string ReadAllText() => File.ReadAllText(path2);
方法运行时平均值比率分配
WriteAllTextoutside_default.png193.50 μs1.0310016 B
WriteAllTextoutside_default.png187.32 μs1.00464 B





ReadAllTextoutside_default.png23.29 μs1.0824248 B
ReadAllTextoutside_default.png21.53 μs1.0024248 B

序列化 (System.Text.Json)

来自System.Text.Json命名空间的JsonSerializer得到了一个小小的升级,一些使用了反射的自定义处理程序会在幕后为你缓存,即使你初始化一个JsonSerialzierOptions的新实例。

private JsonSerializerOptions options = new JsonSerializerOptions();
private TestClass instance = new TestClass("Test");[Benchmark(Baseline = true)]
public string Default() => JsonSerializer.Serialize(instance);[Benchmark]
public string CachedOptions() => JsonSerializer.Serialize(instance, options);[Benchmark]
public string NoCachedOptions() => JsonSerializer.Serialize(instance, new JsonSerializerOptions());public record TestClass(string Test);

在上面代码中,对NoCachedOptions()的调用通常会导致JsonSerialzierOptions的额外实例化和一些自动生成的处理程序。在.NET 7 中这些实例是被缓存的,当你在代码中使用这种方法时,你的性能会好一些。否则,无论如何都要缓存你的JsonSerialzierOptions,就像在CachedOptions例子中,你不会看到很大的提升。

方法运行时平均值比率分配分配比率
Defaultoutside_default.png135.4 ns1.04208 B3.71
CachedOptionsoutside_default.png145.9 ns1.12208 B3.71
NoCachedOptionsoutside_default.png90,069.7 ns691.897718 B137.82
Defaultoutside_default.png130.2 ns1.0056 B1.00
CachedOptionsoutside_default.png129.8 ns0.9956 B1.00
NoCachedOptionsoutside_default.png533.8 ns4.10345 B6.16

基本类型

1. Guid 相等比较

有一项改进,肯定会导致现代应用程序的性能大增,那就是对Guid相等比较的新实现。

private Guid guid0 = Guid.Parse("18a2c952-2920-4750-844b-2007cb6fd42d");
private Guid guid1 = Guid.Parse("18a2c952-2920-4750-844b-2007cb6fd42d");[Benchmark]
public bool GuidEquals() => guid0 == guid1;
方法运行时平均值比率
GuidEqualsoutside_default.png1.808 ns1.49
GuidEqualsoutside_default.png1.213 ns1.00

可以感觉到,新的实现也使用了 SIMD,比旧的实现快 30%左右。

65d06777094b0ce292198c968aceffd0.png

由于有大量的 API 使用Guid作为实体的标识符,这肯定会积极的产生影响。

2. BigInt 解析

一个很大的改进发生在将巨大的数字从字符串解析为BigInteger类型。就我个人而言,在一些区块链项目中,我曾使用过BigInteger类型,在那里有必要使用这种类型来表示 ETH 代币的精度。所以在性能方面,这对我来说会很方便。

private string bigIntString = string.Concat(Enumerable.Repeat("123456789", 100000));[Benchmark]
public BigInteger ParseBigInt() => BigInteger.Parse(bigIntString);
方法运行时平均值比率分配
ParseBigIntoutside_default.png2.058 s1.622.09 MB
ParseBigIntoutside_default.png1.268 s1.002.47 MB
733a8bc07f96fe6cce7e0b12d01ec46e.png

我们可以看到性能有了明显的提高,不过我们也看到它比.NET6 上多分配一些内存。

3. Boolean 解析

对于解析boolean类型,我们也有显著的性能改进:

[Benchmark]
public bool ParseBool() => bool.TryParse("True", out _);
方法运行时平均值比率
ParseBooloutside_default.png8.164 ns5.21
ParseBooloutside_default.png1.590 ns1.00
a3c68cc7781e9e674fa06e7a3ebb15f3.png

诊断

System.Diagnostics命名空间也进行了升级。进程处理有两个重大改进,Stopwatch有一个新功能。

1. GetProcessByName

[Benchmark]
public Process[] GetProcessByName()=> Process.GetProcessesByName("dotnet.exe");
方法运行时平均值比率分配分配比率
GetProcessByNameoutside_default.png2.065 ms1.04529.89 KB247.31
GetProcessByNameoutside_default.png1.989 ms1.002.14 KB1.00

新的GetProcessByName()的速度并不明显,但使用的分配内存比前者少得多。

7bd991cf56011860080c5cd6244c9f9f.png

2. GetCurrentProcessName

[Benchmark]
public string GetCurrentProcessName()=> Process.GetCurrentProcess().ProcessName;
方法运行时平均值比率分配分配比率
GetCurrentProcessNameoutside_default.png1,955.67 μs103.023185 B6.98
GetCurrentProcessNameoutside_default.png18.98 μs1.00456 B1.00

在这里,我们可以看到一个更有效的内存方法,对.NET 7 的实现有极高的性能提升。

c4d3d4a8cdf0c2c2779c8ee7f0bdee9a.png

3. Stopwatch

Stopwatch被广泛用于测量运行时的性能。到目前为止,存在的问题是,使用Stopwatch需要分配堆内存。为了解决这个问题,dotnet 社区实现了一个静态函数GetTimestamp(),它仍然需要一个复杂的逻辑来有效地获得时间差。现在又实现了另一个静态方法,名为GetElapsedTime(),在这里你可以传递之前的时间戳,并在不分配堆内存的情况下获得经过的时间。

[Benchmark(Baseline = true)]
public TimeSpan OldStopwatch()
{Stopwatch sw = Stopwatch.StartNew();return sw.Elapsed;
}[Benchmark]
public TimeSpan NewStopwatch()
{long timestamp = Stopwatch.GetTimestamp();return Stopwatch.GetElapsedTime(timestamp);
}
MethodMeanRatioAllocatedAlloc Ratio
OldStopwatch39.44 ns1.0040 B1.00
NewStopwatch37.13 ns0.94-0.00
1be1f363f23d845e2b4deb8def5afba7.png

这种方法的速度优化并不明显,然而节省堆内存分配可以说是值得的。

结尾

我希望,我可以在性能和基准测试的世界里给你一个有趣的切入点。如果你关于特定性能主题想法,请在评论中告诉我。

如果你喜欢这个系列的文章,请务必关注我,因为还有很多有趣的话题等着你。

谢谢你的阅读!

版权

原文版权:Tobias Streng
翻译版权:InCerry 

原文链接: https://medium.com/@tobias.streng/net-performance-series-1-performance-improvements-in-net-7-fb793f8f5f71

参考资料

[1]

CHUTTERSNAP: https://unsplash.com/@chuttersnap?utm_source=medium&utm_medium=referral

[2]

Unsplash: https://unsplash.com/?utm_source=medium&utm_medium=referral

[3]

dotnet社区: https://github.com/microsoft/dotnet

[4]

BenchmarkDotNet: https://benchmarkdotnet.org/articles/overview.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/281656.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

丁洪波 -- 不要“ 总是拿着微不足道的成就来骗自己”

都市快报实盘大赛25期&#xff1a;于海飞/丁洪波荣获冠亚军 七禾网 时间&#xff1a;2010-11-02 12:47:05 来源&#xff1a;期货中国10月30日下午&#xff0c;2010年浙商期货实盘大赛第三季度&#xff08;都市快报实盘大赛第25期&#xff09;颁奖典礼在天科大厦浙商期货大会议室…

面试专题(Mysql及Mongodb)

2019独角兽企业重金招聘Python工程师标准>>> mysql面试题 1. 各个数据库存储引擎区别 mysql的存储引擎是针对表进行设置的&#xff0c;一个库的不同表可以设置不同的存储引擎&#xff0c;mysql默认支持多种存储引擎&#xff0c;以适用不同领域的数据库应用需要&…

织梦网站翻页php,dedecms织梦网站列表页和内容页分页样式

织梦分页标签{dede:pagelist istitem"index,pre,next,end,option,info," listsize"5"/}&#xff0c;{dede:prenext getpre/}&#xff0c;{dede:prenext getnext/}。默认样式和使用模板css样式布局不一样,这时又不想重写样式&#xff0c;我们可以修改织梦标…

KDD走进阿里 数百专家聚集探讨产学研一体化

6月29日&#xff0c;由阿里巴巴集团、中国中文信息学会、KDD China联合主办的数据挖掘前沿发展与未来论坛在杭州举行&#xff0c;会议吸引了来自国际顶级高校和知名企业的近300名专家学者到场参会、近30000人在线观看。论坛除了分享最新的数据挖掘领域最新科研成果及研发思路外…

php模板引擎循环start,PHP模板引擎Smarty内建函数section,sectionelse用法详解

本文实例讲述了PHP模板引擎Smarty内建函数section,sectionelse用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;section 是 Smarty 模板中除了 foreach 以外的另一种处理循环的方案&#xff0c;section 比 foreach 要灵活&#xff0c;就像是一个改进的 foreach 语句…

OpenHarmony操作系统与龙芯2K1000LA芯片完成适配,龙架构平台获得开源鸿蒙认证

近日&#xff0c;龙芯中科与软通动力控股公司鸿湖万联共同完成OpenHarmony操作系统与龙芯2K1000LA处理器的适配&#xff0c;“乘风1000”开发板&#xff08;搭载龙芯2K1000LA&#xff09;荣获OpenHarmony生态产品兼容性证书。至此&#xff0c;万物互联的OpenHarmony生态体系再次…

struts2开发action 的三种方法以及通配符、路径匹配原则、常量

struts2开发action 的三种方法 1、继承ActionSupport public class UserAction extends ActionSupport {// Action中业务处理方法public String login() {System.out.println("UserAction.login()"); // return "success";return SUCCESS;} } 2、实现…

left join 和 inner join

2019独角兽企业重金招聘Python工程师标准>>> left join 和 inner join 首先 MySQL 中 inner join 的效率确实要高于 left join。所以没必要使用 left join 转弯成 inner join 的效果。这样不但效率降低&#xff0c;可读性也会降低。 Number1 select from t1 left j…

Vue3+.NET6,轻松开发管理后台!(可复用)

在GitHub是没找到简单好用的Vue3.NET6管理后台项目&#xff0c;有收藏的请评论区分享。这里分享一套Vue3 Axios TS Vite Element Plus .NET 6 WebAPI JWT SqlSugar的通用管理后台&#xff0c;前后端分离架构&#xff0c;各种最新框架组件&#xff0c;实现了管理后台几乎…

iOS网络请求安全认证(JWT,RSA)

在网络世界中&#xff0c;安全是一个很重要的问题&#xff0c;以往的HTTP请求已经不能承担这个安全任务&#xff0c;抓包工具一抓&#xff0c;你的所有网络请求全都曝光。当然&#xff0c;你可能会采用加密算法来加密数据&#xff0c;但是这仍然不够。 在移动端和服务器的通信过…

linux下mariadb大小写敏感

2019独角兽企业重金招聘Python工程师标准>>> Linux下安装好mariadb后&#xff0c;在使用时会发现mariadb对大小写敏感&#xff0c;这对开发带来一定的不利&#xff0c;这时只要在配置文件中配置一下&#xff0c;取消大小写敏感即可&#xff1a; sudo vi /etc/MySQL/…

评论列表显示及排序,个人中心显示

1.显示所有评论{% for foo in ques.comments %} 2.所有评论排序uquestion db.relationship(Question, backrefdb.backref(comments, order_bycreat_time.desc)) 3.显示评论条数{{ ques.comments|length }} 1题代码如下&#xff1a; <h3>评论区:({{ ques.comments|length…

他俩都曾是技术大牛,创业这些年来有怎样的苦与乐?

这是头哥侃码的第263篇原创国庆假期回来&#xff0c;「头哥唠 B 唠」的直播仍在继续。这次我邀请了我工作上的老板和朋友&#xff0c;一起聊了聊关于 “技术创业路上的苦与乐”。熟悉他们两位的都知道&#xff0c;可以说是技术出身&#xff0c;然后创业当老板的代表。大家都知道…

maven,gradle本地缓存位置

gradle: 配置系统环境变量GRADLE_USER_HOME即可&#xff0c;值为缓存位置。 maven: 修改settings文件&#xff1a;maven的home路径下的conf文件夹下的settings.xml 对于有些IDEA&#xff0c;还需要配置。但是不要再打开项目后的FILE-->settings配置&#xff0c;而是需要在选…

客户端嵌套 Web 页面如何选择

客户端嵌套 Web 页面如何选择客户端嵌套 Web 页面如何选择作者&#xff1a;驚鏵在使用客户端嵌套WEB页面有一下几种方案&#xff1a;WebView2[1]Electron[2]NW.js[3]sciter[4]miniblink[5]现在国内众多桌面程序都是用了以下五种&#xff0c;因为它跨平台更为方便&#x1f447;。…

【Tomcat】Tomcat配置与优化(内存、并发、管理)【自己配置】

一、JVM内存配置优化 主要通过以下的几个jvm参数来设置堆内存的&#xff1a; -Xmx512m 最大总堆内存&#xff0c;一般设置为物理内存的1/4 -Xms512m 初始总堆内存&#xff0c;一般将它设置的和最大堆内存一样大&#xff0c;这样就不需要根据当前堆使用情况而调整堆的大…

【2018-11-15】中证1000指数的估值详情

中证1000指数选取中证500和沪深300指数样本股以外的&#xff0c;流动性好的1000只股票组成&#xff0c;与沪深300 和中证500 等形成互补。 中证1000的个股大多数是由市场上流通市值排名在 800 到 1800 名之间的个股组成&#xff0c;是一个适用范围较广的小盘指数。 中证1000的…

印度光伏巨头Adani与华为签署500MW采购合同

日前&#xff0c;印度光伏巨头Adani与华为签订了采购合同。Adani未来一年的项目全部采用华为FusionSolar3.0智能光伏解决方案&#xff0c;首期500MW采购合同已经签署&#xff0c;将采购最新的智能光伏控制器&#xff08;组串逆变器&#xff09;SUN2000-43KTL、数据采集器SmartL…

宣布 .NET MAUI 支持 .NET 7 RC 2

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;6分钟)支持 .NET 7 Release Candidate 2 的 .NET 多平台应用程序 UI (MAUI) 现在可在 Windows 和 Mac 上的 Visual Studio 17.4 Preview 4 中使用。RC2 的主要主题是质量和对带有 iOS 16 的 Xcode 14 的 .NET 支持。此…

Uno开发的小游戏

大家好&#xff0c;我是沙漠尽头的狼。刚在微信群里逛&#xff0c;有网友发了Uno的在线小游戏&#xff0c;站长觉得不错&#xff0c;简单分享下&#xff1a;群聊涨见识Uno是什么&#xff1f;使用 C# 和 WinUI 实现像素完美的多平台应用程序&#xff0c;用于构建适用于 Windows、…