.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.pswp.cn/news/281656.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281656.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281656.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

UVA - 10061 How many zero#39;s and how many digits ?

n!x*b^y, 當x為正整數時,最大的y就是n!末尾0的個數了, 把n,b分別拆成素因子相乘的形式: 比如, n5,b16 n5,b2^4, 非常明顯,末尾0的個數為0 10進制時,n!a*10^x b進制時,n!c*b^y 非常明顯,n!的位數就是最大的x1 這里計算我用了log,精度設置為1e-9 #include<iostream> #inclu…

丁洪波 -- 不要“ 總是拿著微不足道的成就來騙自己”

都市快報實盤大賽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;我們可以修改織夢標…

通過中間件添加用戶的Claim

本文主要介紹 Sang.AspNetCore.RoleBasedAuthorization[1] 庫如何通過中間件實現對用戶 Claim 的添加。背景前面我們介紹了通過對自定義授權策略和自定義授權處理程序的使用實現了基本的RBAC權限設計&#xff0c;將大量的用戶可訪問資源及操作的標識直接放到用戶的 JWT Token 中…

部署也是工程的一部分,也要編程(自動化)

部署和開發一樣&#xff0c;同樣面臨變化。同樣有復雜的細節。 同樣應該代碼化&#xff0c;自動化。把復雜性、思路&#xff0c;操作&#xff0c;都固化下來&#xff0c;顯式表達。 不要“雪花”式配置。 把最近看的文章摘抄一下 集句&#xff1a; 1頻繁做讓你感到痛苦的事情&a…

KDD走進阿里 數百專家聚集探討產學研一體化

6月29日&#xff0c;由阿里巴巴集團、中國中文信息學會、KDD China聯合主辦的數據挖掘前沿發展與未來論壇在杭州舉行&#xff0c;會議吸引了來自國際頂級高校和知名企業的近300名專家學者到場參會、近30000人在線觀看。論壇除了分享最新的數據挖掘領域最新科研成果及研發思路外…

zookeeper學習03 使用場景

zookeeper實際應用場景 zookeeper能夠實現哪些場景 1&#xff09;訂閱發布/配置中心 watcher機制 統一配置管理&#xff08;disconf&#xff09; 實現配置信息的集中式原理和數據的動態更新 實現配置中心有倆種模式&#xff1a;push,pull 長輪詢 zookeeper采用的是推拉相結合的…

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、實現…

閉包--閉包作用之保護(一)

閉包作用:保護 形成私有作用域,保護里面的私有變量不受外界干擾例如多人協作開發&#xff1a;A的代碼有fn(),B的代碼有fn(),但是他們不相互影響 // A的代碼<script>(function() {function fn1() {console.log("aa")}window.fn1 fn1;})()// window.fn1() //11&…

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…

oracle 數據庫中拆分,oracle數據庫字符串拆分

第一種 直接返回切分的字符串create or replace function Get_StrArrayLength(av_str varchar2,--要分割的字符串av_split varchar2 --分隔符號)return numberislv_str varchar2(1000);lv_length number;beginlv_str:ltrim(rtrim(av_str));lv_length:0;while instr(lv_str,av_s…

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;但是這仍然不夠。 在移動端和服務器的通信過…

微信小程序黑客馬拉松即將開始,來做最酷的 Mini Program Creators!

微信小程序黑客馬拉松正式啟動 近日&#xff0c;小程序斬獲一項世界級殊榮——作為一項全新的技術和應用創新&#xff0c;小程序首次獲選世界互聯網領先科技成果。目前小程序應用數量已超過 100 萬&#xff0c;覆蓋了 200 多個細分行業&#xff0c;日活用戶達到 2 億。 微信小程…

oracle 文件寫 n r,[oracle]log_archive_dest_n與DB_RECOVERY_FILE_DEST

DB_RECOVERY_FILE_DEST參數是默認的flashrecovery area的路徑&#xff0c;里面存放有歸檔日志、閃回日志以及rman的備份文件等文件。LOG_ARCHIVE_DEST_n參數是存放歸檔日志的路徑&#xff0c;n表示1~10的一個整數&#xff0c;由于歸檔日志在recovery的時候擔當了重要的角色&…

記一次 .NET 某娛樂聊天流平臺 CPU 爆高分析

一&#xff1a;背景 1.講故事前段時間有位朋友加微信&#xff0c;說他的程序直接 CPU100%&#xff0c;每次只能手工介入重啟&#xff0c;讓我幫忙看下到底怎么回事&#xff0c;哈哈&#xff0c;這種CPU打滿的事故&#xff0c;程序員壓力會非常大, 我讓朋友在 CPU 高的時候抓 2 …

linux下mariadb大小寫敏感

2019獨角獸企業重金招聘Python工程師標準>>> Linux下安裝好mariadb后&#xff0c;在使用時會發現mariadb對大小寫敏感&#xff0c;這對開發帶來一定的不利&#xff0c;這時只要在配置文件中配置一下&#xff0c;取消大小寫敏感即可&#xff1a; sudo vi /etc/MySQL/…