C# Async Programming的注意事項

C# Async Programming的注意事項

更新於 發佈於 閱讀時間約 1 分鐘

以下是我在撰寫 C# Async Programming 會關注到的事項,我也是從別人的經驗學來的,也許值得參考。

全面擁抱異步

  • 一旦開始使用 async/await,就應該讓整個應用程序都使用異步模式。
  • 避免混合同步和異步代碼,這可能導致性能問題和 Deadlock。
    • 性能問題:因為 Calling Thread 沒有被釋放。導致桌面應用程式的 UI 凍結;導致 ASP .NET Core 不能服務更多的請求。
    • Deadlock:互相的等待對方釋放資源,造成程式卡住,不會執行後續的程式碼。
// 好的做法
public async Task<int> DoSomethingAsync()
{
var result = await CallDependencyAsync();
return result + 1;
}

// 避免這樣做
public int DoSomething()
{
var result = CallDependencyAsync().Result; // 可能導致死鎖
return result + 1;
}

避免使用 async void

  • 異步方法總是返回 Task 或 Task<T>,而不是 void。
  • async void 可能導致未處理的異常,造成應用程序崩潰。
// 好的做法
public async Task BackgroundOperationAsync()
{
var result = await CallDependencyAsync();
DoSomething(result);
}

// 避免這樣做
public async void BackgroundOperation() // 可能導致未捕獲的異常
{
var result = await CallDependencyAsync();
DoSomething(result);
}

絕不使用 Task.Result 或 Task.Wait

  • 這些方法可能在 UI 應用程序中造成 Deadlock,在服務器應用程序中導致線程池資源耗盡。
  • 始終使用 await 替代。
// 好的做法
public async Task<string> GetDataAsync()
{
var result = await FetchDataAsync();
return ProcessData(result);
}

// 避免這樣做
public string GetData()
{
var result = FetchDataAsync().Result; // 可能導致死鎖
return ProcessData(result);
}

正確傳遞 CancellationToken

將 CancellationToken 參數傳遞給支援的 API。

public async Task<string> DoAsyncThing(CancellationToken cancellationToken = default)
{
byte[] buffer = new byte[1024];
// 正確地將 cancellationToken 傳遞給 ReadAsync
int read = await _stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken);
return Encoding.UTF8.GetString(buffer, 0, read);
}

優先使用 async/await 而非直接返回 Task

使用 async/await 提供更好的異常處理。

// 好的做法
public async Task<int> DoSomethingAsync()
{
return await CallDependencyAsync();
}

// 避免這樣做,除非有性能考慮
public Task<int> DoSomething()
{
return CallDependencyAsync();
}

優先使用 await,不要直接回傳 Task

沒有必要對 Task.FromResult 使用 await,因為這會增加不必要的開銷。

// 好的做法
public Task<int> GetValueAsync()
{
return Task.FromResult(42);
}

// 避免這樣做
public async Task<int> GetValueAsync()
{
return await Task.FromResult(42); // 不必要的 await
}
avatar-img
C# 工匠的 DevOps 旅程
5會員
12內容數
專注於 C#, DevOps 的工程師
留言
avatar-img
留言分享你的想法!
Code Coverage 是什麼? 程式碼覆蓋率(Code Coverage)是一種軟體測試指標,用百分比表示,數值越高越好。
本文介紹瞭如何在C#專案中建立和使用packages.lock.json檔案,以確保每次執行dotnet restore時都可以獲得相同的packages集合。我們還討論了dotnet restore抓取不同packages的原因,並提供了相關的解決方案。
Semgrep 是一個功能強大的 SAST 工具,可以幫助開發人員早期發現程式碼中的安全問題,本文介紹如何將 Semgrep 整合到 GitLab Pipeline 以進行 SAST 掃描。
Code Coverage 是什麼? 程式碼覆蓋率(Code Coverage)是一種軟體測試指標,用百分比表示,數值越高越好。
本文介紹瞭如何在C#專案中建立和使用packages.lock.json檔案,以確保每次執行dotnet restore時都可以獲得相同的packages集合。我們還討論了dotnet restore抓取不同packages的原因,並提供了相關的解決方案。
Semgrep 是一個功能強大的 SAST 工具,可以幫助開發人員早期發現程式碼中的安全問題,本文介紹如何將 Semgrep 整合到 GitLab Pipeline 以進行 SAST 掃描。