進一步了解Rider或申請免費試用,歡迎咨詢JetBrains授權合作伙伴-龍智。

任務并行庫 (TPL) 是所有 .NET 應用程序的基礎,允許框架編寫和執行多線程和并行代碼。此外,想要充分利用資源的開發者可能會借助 System.Threading 和 System.Threading.Tasks 中的類型編寫自定義代碼。只有掌握并發和線程的基礎,包括鎖定、死鎖、await 和計劃,才能編寫出快速且可擴縮的解決方案。要擴展對這些概念的理解,部分需要優秀的工具來協助呈現和分析任務執行的繁雜本質。此前,JetBrains推出了 Tasks(任務)視圖的第一次迭代,這個強大工具旨在幫助您了解當前應用程序流程中的既有任務。本文將探究新的工具窗口,探討其基本 UI 元素,并演示一些常見場景。最后,您將有能力探索自己的代碼庫并發現優化機會。
.NET 應用程序中的任務執行
在 .NET 中,Tasks(任務)提供了對并發和多線程等概念的抽象。其中的想法是減少對 CPU 核心和線程的顧慮,并處理并發計劃和執行工作的高級概念。這通常很棒,因為它可以幫助開發者編寫更多命令式代碼,同時有效利用所有系統資源。雖然抽象相當不錯,但沒有一種抽象是完美的,而且有些時候,您必須同時處理多個任務的麻煩。其中包括死鎖、競爭條件和導致背壓的低效計劃。處理抽象并不意味著您不應該理解它們的運作方式和原因。通常,您負責計劃任務,但不知道這些任務何時以及如何完成。執行是 .NET 運行時的工作。雖然您可能會看到預示問題即將發生的特定代碼模式,但診斷 Tasks(任務)問題的最佳方式是在運行時。下文將展示代碼庫中的一些常見場景,以及 Tasks(任務)視圖如何幫助您更好地理解您的應用程序。
常用任務
處理任務時,最可能出現的情況是使用的 API 會返回需要 async 和 await 關鍵字的任務。這些異步 API 位于 ASP.NET Core、MAUI 和 Entity Framework Core 中。許多開源項目也已轉向異步優先 API 來支持開發者需求。我們來看一個簡單的示例。
await BasicWork(); async Task BasicWork() { await Task.Delay(TimeSpan.FromSeconds(1)); Console.WriteLine(" Hello Tasks View!"); }
在這個示例中,有兩個任務:源自我們程序的主要任務和 BasicWork 方法。可以使用新的 Tasks(任務)視圖來確認這一點。在調試會話中,點擊 Tasks(任務)標簽頁查看下表。

選擇右上角的選項可以切換到 Graph(圖表)視圖。

將鼠標懸停在任意堆棧條目上即可在圖表視圖中查看行信息。

處理任務時,任何任務在任何時候都會具有以下五種狀態之一:
- Active(有效):目前正在執行和運行。
- Scheduled(已計劃):任務已創建,但尚未執行。
- Awaiting(等待):任務已經等待,但可能正在等待其他任務。
- Blocked(阻塞):任務位于堆棧頂部,執行線程被阻塞(睡眠、等待鎖等)。堆棧中還有一些更高級別的任務。
- Deadlocked(死鎖):任務正在爭用資源,并且存在嚴重問題。
接下來看一看父任務。
父任務
通過父級操作,開發者可以按邏輯對任務進行分組。在任務中創建任務時,您可以使用 TaskCreationOptions.AttachedToParent 將新任務與包含任務綁定。
await ParentedTasks(); Task ParentedTasks() { // Parent task var parentTask = Task.Factory.StartNew(() => { Console.WriteLine("Parent task started."); // Child task var task = Task.Factory.StartNew(() => { Console.WriteLine("Child task started."); Task.Delay(2000).Wait(); // Simulating some work Console.WriteLine("Child task completed."); }, TaskCreationOptions.AttachedToParent); Console.WriteLine("Parent task doing some work."); }, TaskCreationOptions.AttachedToParent); // Wait for parent task to complete, which includes the children parentTask.Wait(); Console.WriteLine("Parent task completed."); return Task.CompletedTask; }
運行代碼并查看 Tasks(任務)視圖,您可以看到我們已經成功為子任務設置父任務。

請注意,每個新任務都有一個由 .NET 運行時指定的整數 Id。這些標識符有助于跟蹤當前流程中存在的任務。這次,圖表視圖顯示由 ParentedTasks 代碼產生的兩個異步邏輯堆棧,該代碼使用類似于 Wait 的方法并返回 Task.CompletedTask。

很好, 了解任務是相關還是已創建單獨邏輯堆棧,可以幫助您了解是否創建了潛在的競爭條件。接下來看看 Tasks(任務)視圖如何幫助了解工作的計劃方式。
計劃任務
await 一項任務時,您可以有效地將工作安排在未來的時間。這項工作可以在計劃任務之后立即進行,也可以在執行其他計劃任務之后進行。在下面的示例中,我們計劃了幾個任務并等待它們完成。
await ScheduledWork();async Task ScheduledWork() { Console.Write("Let's work..."); var tasks = Enumerable .Range(1, 10) .Select((i) => Task.Run(() => Console.Write(i))); await Task.WhenAll(tasks); }
通過 Task.WhenAll 嘗試執行所有提供的任務,所有任務都計劃在未來執行。您可以在 Tasks(任務)視圖中看到此信息。

此外,使用 Task.WhenAll 會創建異步邏輯堆棧,所有操作都可以在該堆棧下運行。

在調試會話期間逐步執行代碼時,您將看到 Tasks(任務)列表隨著任務完成而縮減。您可能還會注意到多個任務在同時執行。

看著任務完成當然感覺棒極了,但這個過程也不應該沒完沒了。接下來,是處理任務時最可怕的情況:死鎖。
死鎖
死鎖最常見的原因是對某種鎖定機制保護的共享資源的爭用。鎖定在處理共享資源時必不可少,但可能導致應用中斷問題。
創造一個死鎖, 一起來了解 Tasks(任務)視圖如何幫助我們識別它。我們將計劃兩個任務,每個任務都嘗試鎖定相同的變量。
await Deadlock(); // This method will cause a deadlock // proceed with caution, oOOoOOoOo! async Task Deadlock() { object one = new(); object two = new(); var timer = new System.Timers.Timer( TimeSpan.FromSeconds(2) ) { Enabled = true, AutoReset = false }; timer.Elapsed += (_, _) => { // only see this if we're deadlocked Console.WriteLine("Deadlock"); }; await Task.WhenAll(Task.Run(() => { Console.WriteLine("Getting lock for one."); lock (one) { Thread.Sleep(1000); Console.WriteLine("Getting lock two in first task."); lock (two) { } } }), Task.Run(() => { Console.WriteLine("Getting lock two in second task."); lock (two) { Thread.Sleep(1000); Console.WriteLine("Getting lock one in second task."); lock (one) { } } })); }
運行代碼時,您會發現應用程序不會退出。在 Run(運行)工具欄中,點擊暫停按鈕來暫停應用程序。糟了,死鎖!太震驚了!(其實也沒有很震驚)。

圖表視圖更能說明問題,它展示了兩個競爭的任務及其原因。

雙擊任意一個死鎖的邏輯堆棧都會將您帶到死鎖的位置。

這種便捷的導航應該可以讓查找和解決死鎖變得非常簡單。
結論
Tasks(任務)視圖目前在 JetBrains Rider 2024.2 EAP 中可用,期待您的反饋。任務可能是 .NET 開發的挑戰性部分,希望額外的工具可以幫助您克服這些挑戰。嘗試一下,看看它是否可以幫助您優化現有代碼或找到代碼庫中存在已久的問題。
本博文英文原作者:Khalid Abuhakmeh
關于 JetBrains Rider
JetBrains Rider 可以幫助您在 Windows、Mac 和 Linux 上開發完整的 .NET 應用程序和 Web 項目,以及 Unity、Unreal Engine 和基于 Godot 的游戲。它為 .NET 開發中使用的所有主要語言提供了優異的編輯支持和代碼洞察,這些語言包括 C#、F#、Razor、Blazor 語法、JavaScript、TypeScript、XAML、HTML、CSS 和 SQL。JetBrains Rider 將 ReSharper 豐富的代碼檢查、上下文操作和重構與 IntelliJ 平臺強大的 IDE 功能集和 Rider 自身的 .NET 特色融合在一起。盡管功能非常豐富,但 IDE 在不同平臺上仍然能夠快速運行和響應。
-
.NET
+關注
關注
0文章
48瀏覽量
24282 -
jetbrains技術
+關注
關注
0文章
6瀏覽量
111
發布評論請先 登錄
機智云開發者大會視頻分享,帶你近距離解析物聯網
絕對干貨!HarmonyOS開發者日資料全公開,鴻蒙開發者都在看
喜報|HarmonyOS開發者社區連獲業內獎項,持續深耕開發者生態
Microchip MPLAB X IDE 任務列表功能

龍芯.NET正式發布 開源共享與開發者共成長
華為開發者大會主要內容 華為開發者大會2021年必看

2021年華為開發者大會亮點紛呈 OpenHarmony、智能硬件、HarmonyOS架構解析

供鴻蒙開發者使用的計數動畫文本視圖
無距離編程,使用JetBrains Rider進行遠程開發
JetBrains IDE中AI Assistant功能示例

Google Calendar、Tasks和Keep應用將整合Gemini模型
JetBrains IDE上架開發微信小程序的官方插件

【Android開發者必看】使用JetBrains TeamCity為Android項目構建CI/CD管道詳細指南

實戰教程:使用JetBrians Rider快速部署與調試PS5和Xbox上的UE項目

評論