.NET微服務系統(tǒng)遷移至.NET6.0的故事
本次遷移涉及的是公司內(nèi)部一個業(yè)務子系統(tǒng),該系統(tǒng)是一個多樣化的應用,支撐著公司的多個業(yè)務方向。目前,該系統(tǒng)由40多個基于.NET的微服務應用構成,使用數(shù)千個CPU核心和數(shù)TB內(nèi)存,在數(shù)百個Linux容器中運行。每天,該系統(tǒng)需要處理數(shù)十億次請求。
該系統(tǒng)其中大部分服務是在2018-2019年左右由老舊.NET Faremwork、Java等系統(tǒng)重構而來,當時使用的是.NET Core 2.1,這幾年業(yè)務迭代陸續(xù)新建了一些服務,所以該系統(tǒng)大部分服務是.NET Core 2.1,也有小一部分采用的是.NET Core 3.1和.NET5.0。
如今5年過去了,.NET的版本已經(jīng)來到了7.0,相較于之前的版本它加入了非常多先進的特性、提升了性能、加入可觀測性支持、更加適應容器化環(huán)境的部署;而現(xiàn)在的.NET Core 2.1讓我們有很多性能提升和新的特性都無法享受到。
為了享受更新的特性和性能提升,我們團隊在最近的一段時間里面完成了.NET Core 2.1和.NET 5.0向.NET 6.0的遷移,其中發(fā)生踩了一些坑,最后也獲得了不錯的結果,特意在這里和大家分享這整個過程。
為什么不是向.NET 7.0遷移?首先是因為.NET7.0在我們內(nèi)部中的組件還沒得到很好的支持,另外.NET6.0是LTS版本而.NET7.0不是;而且從.NET6.0向.NET7.0遷移非常簡單,后續(xù)可以直接升級。所以綜合考慮,我們決定先升級到.NET6.0版本。
為什么是.NET
那么有很多朋友會有疑問,現(xiàn)在有很多面向云原生的編程語言和框架,我們?yōu)槭裁催x擇了使用.NET?我想從幾個方面解答這個問題。
歷史原因
.NET見證了互聯(lián)網(wǎng)的起步階段,很多大家能想到的互聯(lián)網(wǎng)應用一開始都是基于.NET技術構建,特別是在我們這個行業(yè)更是如此;下圖是統(tǒng)計十多個微服務項目代碼,可以發(fā)現(xiàn)有近700萬行.NET代碼(包括C#、ASP.NET、Razor等等),所以對于我們來說,繼續(xù)在.NET上投資是一個很好的選擇,沒有什么理由更換其它的技術。

生產(chǎn)力和性能
大家都知道,在.NET平臺上可以運行很多語言,比如C#、F#、JavaScript、PHP、Python等等,其中使用量最大的就是C#,而C#它有很多先進的語法特性,可以極大的提升我們的生廠力和程序的能。比如:
- 泛型:泛型是一個普遍存在的特性,它允許將類專門化為一種或多種類型。例如,
List<T>是一個開放的泛型類,而像List<string>和List<int>這樣的實例化則避免了對單獨的ListOfString和ListOfInt類的需求,或者像ArrayList那樣依賴于對象和轉(zhuǎn)換。泛型還能夠在不同的類型之間創(chuàng)建有用的系統(tǒng)(并減少對大量代碼的需求),比如泛型數(shù)學。另外,C#的泛型不是泛型擦除,而是運行時生成泛型本機代碼,對于值類型可以避免裝箱拆箱,極大降低GC壓力。 - 委托和lambda:委托和 Lambda 表達式允許將方法作為數(shù)據(jù)進行傳遞,這使得將外部代碼集成到由另一個系統(tǒng)擁有的操作流程中變得容易。它們是一種“粘合代碼”,它們的簽名通常是泛型的,以允許廣泛的實用性。
- 擴展方法和Linq:擴展方法允許向現(xiàn)有類添加新方法,而不需要修改類的源代碼,極大增強了擴展性,而最著名的例子就是LINQ,它一種功能強大查詢語言,允許使用類似 SQL 的語法查詢各種數(shù)據(jù)源。它包括標準查詢運算符,如 Where、Select、OrderBy 和 GroupBy 等,它還支持查詢延遲執(zhí)行、類型推斷和強類型查詢等特性,可以非常方便的在代碼中實現(xiàn)數(shù)據(jù)處理。
- 自定義值類型和棧上分配:值類型和棧上分配的內(nèi)存相對于.NET的受GC管理的類型提供了更直接、低級的數(shù)據(jù)和本機平臺交互控制。.NET中的大多數(shù)原始類型,如整數(shù)類型,都是值類型,用戶可以定義具有類似語義的自定義值類型。完全支持值類型。NET 的泛型系統(tǒng),這意味著像
List<T>這樣的泛型類型可以提供扁平的、無開銷(無需裝箱拆箱)的值類型集合。另外.NET泛型在替換值類型時提供專門的編譯代碼,這意味著這些泛型代碼路徑可以避免昂貴的GC開銷。 - 無棧協(xié)程與異步:異步編程是一種基于任務(Task)和異步操作(Async Operation)的并發(fā)模型,可以使用 async/await 關鍵字來實現(xiàn),我們叫它無棧協(xié)程。異步編程中的代碼可以在等待異步操作完成時繼續(xù)執(zhí)行其他任務,從而充分利用 CPU 和 IO 資源,提高程序的并發(fā)性和響應性。異步編程通常用于處理 IO 密集型任務,比如網(wǎng)絡通信、文件操作等。
- 直接操作內(nèi)存:C#原生支持指針,可以很方便的直接操作內(nèi)存,在后續(xù)的版本中,更是提供了安全的內(nèi)存操作庫,例如Span、Memory、Unsafe等,它們可以繞過C#內(nèi)存管理機制,直接操作內(nèi)存。這種方式在一些場景下可以帶來媲美C/C++的性能。
另外在一些編程語言和框架性能排行上,C#和.NET的性能也是名列前茅的。在TechEmpower發(fā)布的WEB框架性能天梯中,基于C#和.NET構建的ASP.NET Core框架排名第七,在功能完備的WEB框架中僅次于Rust和C++框架。
https://www.techempower.com/benchmarks/#section=data-r21&test=composite

在科學計算的Benchmaks Game中,C# .NET名列第5,僅次于C、C++、Rust等一些編譯型語言;執(zhí)行速度是JIT語言中最快的,內(nèi)存占用也是JIT語言中最低的。
https://benchmarksgame-team.pages.debian.net/benchmarksgame/index.html

在評測GRPC性能的grpc_bench中,C#和.NET以141906req/s的速度和5.76ms的平均延時取的了第一的成績。
https://github.com/LesnyRumcajs/grpc_bench/discussions/310

可以看到C#語言和.NET框架在極致的性能和生產(chǎn)力之間取得了很好的平衡,我們恰恰就是需要這樣的框架。
法律風險
C# 和 .NET現(xiàn)階段都是用MIT協(xié)議開源,允許使用者在滿足一些簡單條件的前提下,自由地使用、復制、修改和分發(fā)軟件,因為MIT協(xié)議非常寬松,使用者可以自由地使用和分發(fā)軟件,不必擔心任何版權或?qū)@麊栴}。
遷移過程
此次遷移要最大的保證業(yè)務兼容性,就是不修改任何一行業(yè)務代碼,只進行框架遷移。所以實際上改動非常小,幾乎沒有占用什么測試人力,因為只需要回歸一些主要業(yè)務流程。
代碼遷移
在遷移過程中踩了一些坑,其實這些不應該說是遷移中踩的坑,因為在.NET社區(qū)的文檔中,有非常完整的遷移流程,跟著遷移流程來不會有什么問題,只是有一些要注意的地方。下方是.NET社區(qū)提供的每個版本的遷移文檔:
有一些需要注意的地方,主要是以下幾點:
System.Text.Json序列化
我們主要是WebAPI站點,從.NET Core 2.1升級過程中首先遇到的第一個問題就是序列化的支持,因為以前的版本都是使用的Newtonsoft.Json,在.NET Core 3.1以后默認使用System.Text.Json;雖然System.Text.Json更加規(guī)范和性能更強,但是不會兼容一些非規(guī)范的JSON,為了避免接口契約的變化,我們使用Newtonsoft.Json替換了System.Text.Json。
// 根據(jù)不同的服務類型,選擇不同的配置
services.AddMvc().AddNewtonsoftJson();
services.AddControllers().AddNewtonsoftJson();
services.AddControllersWithViews().AddNewtonsoftJson();
services.AddRazorPages().AddNewtonsoftJson();
Endpoint處理
.NET新版本使用Endpoint進行路由關系,如果之前配置了app.UseMvc(),而且進行了路由設置,如果不想遷移的話那么需要關閉Endpoint的路由支持來兼容。
services.AddMvc(options=>{
options.EnableEndpointRouting = false;
});
異步Action處理
如果以前是.NET2.1版本,Controller中有Async結尾的Action,那么在新版本中Async結尾會默認去除,為了保證應用接口契約兼容性,我們關閉這個特性的支持。
services.AddMvc(options=>{
options.SuppressAsyncSuffixInActionNames = false;
});
重復讀流
如果以前是.NET2.1版本,在某些場景中,需要多次讀取請求正文,則需要在app.UseMvc()或者app.UseEndpoints()前進行request.EnableRewind();,在新版本需要改為Request.EnableBuffering();。
app.Use(async (context, next) =>
{
context.Request.EnableBuffering();
await next(context);
});
并且在使用完成以后需要重置 request.Body.Position = 0;,不過我們并不建議這樣做,高性能的做法是使用PipeReader來讀流。
request.Body.Position = 0;
using (var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
{
......
}
request.Body.Position = 0;
同步讀流
如果以前是.NET2.1版本,默認同步讀request.body流 ,在新版本中為了性能默認就是異步讀,如果不想修改為異步讀流(為了性能不建議同步讀流),那么需要允許同步讀流。
services.Configure<KestrelServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
啟用動態(tài)PGO
.NET5.0以后的一個新的特性,就是Dynamic Profile-guided Optimization(動態(tài)配置引導優(yōu)化),它會在運行時收集代碼的運行情況,通過分層編譯自動對代碼進行優(yōu)化。在其它博主的評測中,某些場景中有高達32%的提升。
# 配置環(huán)境變量
export DOTNET_ReadyToRun=0 # 禁用 AOT
export DOTNET_TieredPGO=1 # 啟用分層 PGO
export DOTNET_TC_QuickJitForLoops=1 # 為循環(huán)使用 tier0代碼

發(fā)布計劃
我們的發(fā)布計劃基本也是進行灰度發(fā)布,可以在7層網(wǎng)關對新舊應用進行流量權重分配,更簡單的方式就是直接替換集群內(nèi)的某些容器鏡像達到流量切換的效果,我們選擇更簡單的方式來處理。

在觀察一段時間沒有問題以后,陸續(xù)覆蓋20%、50%、100%的應用,完成切流。
遷移結果
關于性能的提升
遷移后我們驚喜的發(fā)現(xiàn)整體的性能都有較大的提升,在某個計算密集型的服務中,CPU占用率降低30%,而且沒有了CPU毛刺,占用率曲線更加穩(wěn)定。

另外內(nèi)存也有一定的下降,雖然這個服務占用的內(nèi)存很少,不過也是肉眼可見的進步。

在其它服務中,也觀測到了類似的改變,幅度變得更大。

在IO密集型的應用中,我們也驚喜的觀測到了CPU使用率的下降,而且毛刺變少了很多。

我們知道在.NET的新版本中,著重優(yōu)化了P95耗時,查看了一些接口的平均耗時,發(fā)現(xiàn)相較原來平均耗時降低了50%,非常明顯。

更完善的觀測指標
公司架構團隊基于Opentelemetry完善了.NET上的觀測指標,現(xiàn)在我們可以無侵入無埋點的對應用進行監(jiān)控,還有一些更底層的.NET運行指標也可以監(jiān)控。


比起以前的APM,現(xiàn)在也有更詳細的鏈路數(shù)據(jù)展示。


性能提升來自哪里?
升級.NET6.0以后,帶來了很大的性能提升,在降低CPU和內(nèi)存占用的情況下,還降低了P95延時,這一切的背后是什么?
在每年11月.NET即將發(fā)布正式版之前,.NET社區(qū)都會總結一個長達數(shù)十頁的文檔,從JIT、GC、線程各個方面記錄從上一個版本到這一個版本有哪些性能的提升,可以看到.NET社區(qū)為性能提升做的努力。
筆者帶大家從.NET Core 2.0開始,看看每個版本中有哪些令人印象深刻的性能改進。
.NET Freamwork 到 .NET Core 2.0
.NET Freamwork 到 .NET Core 性能提升:
https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core/
這是一個跨時代的版本,標志了.NET從此走向開源、跨平臺,當然在整個跨平臺構建過程中,也有很多重大性能進步,下面列出了比較重大的部分:
- 集合類型的改進:集合是任何應用程序的基石,.NET 庫中提供了大量集合。并非每個集合上的每個操作都能做得更快,但許多操作都優(yōu)化的更快了。其中一些改進是因為消除了開銷,例如簡化操作以實現(xiàn)更好的內(nèi)聯(lián)、減少指令數(shù)等。比如:
Queue類吞吐量提升了6倍、ConcurrentBat吞吐量提高了~30%,而且極大的降低了GC次數(shù)。 - LINQ:LINQ 中的許多運算符已針對 .NET Core 進行了完全重寫,以便減少分配的數(shù)量和大小、降低算法復雜性,并通常消除不必要的工作。比如:
Select()吞吐量提升了4倍,ToArry()性能提升了6倍。 - 文本處理:.NET 應用程序中另一種非常常見的計算形式是文本處理,在堆棧的各個級別上進行了大量改進。比如:正則表達式吞吐量提高了70%,內(nèi)存分配減少了231%;對于枚舉類的
ToString()吞吐量提高了33%,內(nèi)存分配減少了25倍。 - 網(wǎng)絡:網(wǎng)絡現(xiàn)在是一大重點領域,未來可能會更加如此。正在投入大量精力來優(yōu)化和調(diào)整網(wǎng)絡堆棧的較低級別,以便可以有效地構建更高級別的組件。比如:
Socket鏈接的寫入和接收都減少50%以上的內(nèi)存開銷。 - 并發(fā):線程處理和并發(fā)性相關的基礎設置也有許多改進,比如:
ThreadPool中優(yōu)化了隊列算法,提升了30%的吞吐量,減少了25%的內(nèi)存分配。
.NET Core 2.1
.NET Core 2.1 性能提升: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-2-1/
.NET Core 2.1 雖然和 .NET Core 2.0只有一個小版本的區(qū)別,但是實際上是經(jīng)過一年多的開發(fā)和優(yōu)化,其中比較重大的變更有:
- JIT(即時編譯器): 在改進 .NET Core 2.1 中的實時 (JIT) 編譯器方面進行了大量工作,其中進行了許多優(yōu)化,以增強各種庫和應用程序。其中許多改進都是根據(jù)BCL本身的需求尋求的,使這些改進既有針對性又有廣泛的影響。比如:
EqualityComparer<T>提升了2.5倍性能、Enum.HasFlag()提升了50倍性能。 - 線程:這些改進有多種形式,無論是在減少低級操作的開銷方面,還是在減少常用線程原語中的鎖爭用方面,或是在減少分配方面,或是在總體上改進異步方法背后的基礎設施方面。比如:訪問線程靜態(tài)區(qū)提升20%性能、
Timer計時器提升了50%的吞吐量、異步訪問熱路徑減少了30%開銷。 - String:著重優(yōu)化了
String的性能,使用了向量化、Span<T>等方案,比如:Equals方法吞吐量提升了30%、IndexOf方法吞吐量提升了3倍、ToLower/ToUpper提升了1倍。
.NET Core 3.0
.NET Core 3.0性能提升:
https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/
.NET Core 3.0 提供了大量的功能,從Windows窗體和WPF,到單文件可執(zhí)行文件,到異步枚舉,到平臺內(nèi)在因素,到HTTP/2,到快速JSON讀寫,到匯編可卸載性,到增強的加密技術,等等...有大量的新功能值得興奮。然而,對我來說,性能是讓我早上上班時感到興奮的主要功能,而在.NET Core 3.0中,有大量的性能優(yōu)化點。其中重大改進有:
- Span和它的朋友們:.NET Core 2.1中引入的一個更顯著的特性是
Span<T>,以及它的朋友ReadOnlySpan<T>、Memory<T>和ReadOnlyMemory<T>。這些新類型的引入帶來了數(shù)百種與之交互的新方法,有些是在新類型上,有些是在現(xiàn)有類型上的重載功能,還有及時編譯器(JIT)中的優(yōu)化,使其工作非常高效。 - JIT(即時編譯器):NET Core 3.0最有影響力的變化之一是分層編譯,要做的分析越多,要應用的優(yōu)化越多,需要的時間越長。因此,一開始使用R2R帶實現(xiàn)更快的啟動,但隨后發(fā)現(xiàn)經(jīng)常使用的方法可以通過分層編譯重新編譯,編譯更高性能的代碼。
.NET 5
.NET5性能提升:
https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/
.NET 5已經(jīng)有了大量的性能改進,文中重點介紹了~250個合并請求,這些請求為整個.NET 5的性能改進做出了巨大的貢獻。其中重大改進有:
- GC:對于任何對 .NET 和性能感興趣的人,垃圾回收通常是頭等大事。此版本對于改進GC做了很多努力,比如:并發(fā)GC中使用偷竊算法配平每個線程任務、減少GC掃描靜態(tài)數(shù)據(jù)鎖爭用、使用向量化優(yōu)化GC排序算法等等。
- JIT(即時編譯器):.NET 5 對于即時 (JIT) 編譯器來說也是一個令人興奮的版本,其中許多改進都進入了發(fā)布。與任何編譯器一樣,對 JIT 所做的改進可能會產(chǎn)生廣泛的影響。通常,單個更改對單個代碼段的影響很小,但這些更改隨后會因它們應用的位置數(shù)量而放大。比如:JIT和GC配合向量化初始內(nèi)存、自動優(yōu)化邊界檢查、自動優(yōu)化協(xié)變檢查、自動優(yōu)化重復異常拋出等等。
- 向量化:在 .NET Core 3.0 中,JIT 添加并識別了一千多種新的硬件內(nèi)部方法,使 C# 代碼能夠直接面向 SSE4 和 AVX2 等指令集編程,而在.NET5.0中,增加了數(shù)千個用于ARM架構的向量化方法,使向量化能在ARM架構芯片上工作良好。
.NET 6
.NET 6 性能提升: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/
這無疑是.NET社區(qū)通力協(xié)作的一年,.NET6.0總共有超過6500個合并請求,上文整理了~400個關于性能提升的請求,當時.NET社區(qū)喊出的口號就是這是最快的.NET版本。其中重大改進有:
- JIT:代碼生成是構建其他所有內(nèi)容的基礎。因此,對代碼生成的改進具有倍增效應,能夠提高平臺上運行的所有代碼的性能。.NET 6 在 JIT(即時編譯器)中看到了令人難以置信的大量性能改進。特別是Dynamic PGO(配置引導優(yōu)化),還有其它優(yōu)化如:更強大的去虛擬化支持、更強大的方法內(nèi)聯(lián)支持、值類型寄存器分配優(yōu)化等等。
- GC:在 GC(垃圾回收器)上的 .NET 6 中發(fā)生了大量工作,其中絕大多數(shù)工作都是以將 GC 實現(xiàn)將Segment分配切換為Region分配,達到更快的升代和整理速度。另外還有:優(yōu)化前臺GC的表現(xiàn)、進一步均勻化所有GC堆的任務、增加基于時間衰減算法減少GC。
- 線程池:首先,自 .NET 6 起,runtime 中默認的線程池實現(xiàn)從 C++ 代碼改為了 C#,另外.NET6的線程池引入了一種新的啟發(fā)式算法(hill-climbing)爬山算法注入線程,可有效的降低當任務過多時線程池饑餓的情況。
- 文件IO:.NET 6 中的有大量工作修復 .NET 中最古老的類型之一的性能:每個應用和服務都讀取和寫入文件。不幸的是,多年來也一直受到許多與性能相關的問題的困擾,其中大部分是其在Windows上的異步I/O實現(xiàn)的一部分。在.NET6中,完全重寫了這一部分,在Windows和Unix上都得到了巨大的性能改進。
.NET 7
.NET 7 性能提升: https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/
.NET 7毫無疑問的說,它是迄今為止最快的.NET版本,它性能提升是非常巨大的,以至于筆者打開上面性能優(yōu)化的說明網(wǎng)頁,瀏覽器足足卡頓了幾十秒。.NET 7相較于.NET 6有多達7000多個提交,其中有1000多個是和性能息息相關的,上文只挑選了500個提交。其中重大改進有:
- JIT:在.NET7中,JIT迎來了非常大的改進,其中最大的改進就是分層編譯支持了棧上替換(OSR),支持了ARM64芯片架構,另外Dynamic PGO迎來了更多的改進,優(yōu)化面更加廣泛,比如:消除邊界檢查、循環(huán)提升和復制、常量替換、向量化、自動內(nèi)聯(lián)等等。
- NativeAOT:在.NET7中,NativeAOT正式發(fā)布,意味著.NET代碼可以直接編譯為機器碼,無需運行時,它可以讓系統(tǒng)體積更小、啟動速度更快、內(nèi)存占用更少。
- 反射:同樣優(yōu)化了反射的性能,反射可以讓我們動態(tài)的訪問類型、方法還可以動態(tài)生成代碼,但是它一直都是一個性能陷阱,在.NET7中著重的優(yōu)化了反射的性能,在某些場景可以達到80%的性能提升。
- 線程*:線程是影響每個應用程序的橫切關注點之一,因此線程空間的更改可能產(chǎn)生廣泛的影響。這個版本看到了 ThreadPool 本身的兩個非常重大的變化; 將“IO線程池池”切換到使用一個完全C#代碼的實現(xiàn)(而之前的 IO 池仍然在C++代碼中,即使工作者池在以前的版本中已經(jīng)完全移動到托管) ,另外將
Timer實現(xiàn)從基于C++的實現(xiàn)切換到完全C#代碼中的實現(xiàn)。兩者均提升了將近30%的性能。
總結
總的來說,本次.NET6.0的遷移還是非常成功的,簡單的通過版本升級就能獲得性能提升,而且還可以享受新版.NET和C#帶給我們新的特性,如果有什么問題請私信或者評論,歡迎交流!
其它文章
遷移至.NET5.0后CPU占用降低: https://twitter.com/stebets/status/1442417534444064769
StackOverflow遷移至.NET5.0: https://twitter.com/juanrodriguezce/status/1428070925698805771
StackOverflow遷移至.NET6.0: https://wouterdekort.com/2022/05/25/the-stackoverflow-journey-to-dotnet6/
必應廣告活動平臺遷移至.NET6.0: https://devblogs.microsoft.com/dotnet/bing-ads-campaign-platform-journey-to-dotnet-6/
Microsoft Commerce的.NET6.0遷移之旅: https://devblogs.microsoft.com/dotnet/microsoft-commerce-dotnet-6-migration-journey/
Microsoft Teams服務到.NET6.0的旅程: https://devblogs.microsoft.com/dotnet/microsoft-teams-assignments-service-dotnet-6-journey/
OneService 到 .NET 6.0的旅程 :https://devblogs.microsoft.com/dotnet/one-service-journey-to-dotnet-6/
Exchange 在線版遷移至 .NET Core: https://devblogs.microsoft.com/dotnet/exchange-online-journey-to-net-core/
Azure Cosmos DB 到 .NET 6.0的旅程: https://devblogs.microsoft.com/dotnet/the-azure-cosmos-db-journey-to-net-6/
.NET性能優(yōu)化交流群
相信大家在開發(fā)中經(jīng)常會遇到一些性能問題,苦于沒有有效的工具去發(fā)現(xiàn)性能瓶頸,或者是發(fā)現(xiàn)瓶頸以后不知道該如何優(yōu)化。之前一直有讀者朋友詢問有沒有技術交流群,但是由于各種原因一直都沒創(chuàng)建,現(xiàn)在很高興的在這里宣布,我創(chuàng)建了一個專門交流.NET性能優(yōu)化經(jīng)驗的群組,主題包括但不限于:
- 如何找到.NET性能瓶頸,如使用APM、dotnet tools等工具
- .NET框架底層原理的實現(xiàn),如垃圾回收器、JIT等等
- 如何編寫高性能的.NET代碼,哪些地方存在性能陷阱
希望能有更多志同道合朋友加入,分享一些工作中遇到的.NET性能問題和寶貴的性能分析優(yōu)化經(jīng)驗。目前一群已滿,現(xiàn)在開放二群。
如果提示已經(jīng)達到200人,可以加我微信,我拉你進群: ls1075
另外也創(chuàng)建了QQ群,群號: 687779078,歡迎大家加入。


浙公網(wǎng)安備 33010602011771號