優雅的使用CancellationToken取消一個任務


影片連結


什麼情況下會取消一個任務?

我們在日常生活中的專案中,會碰到長時間等待;使用者關閉瀏覽器的同時,讓背後需要花時間運行的工作停止,這樣做的好處是防止不必要的資源消耗,或是UI介面上有取消的按鈕可以讓使用者做互動的時候進行取消。

我相信大部分的開發人員並沒有實作這樣的Code(沒錯我也是🫠),但其實處理取消非同步或長時間同步作業是必須要被考慮進去的,想當年我剛成為開發人員的時候就有收到這樣的任務,使用者下載檔案的時候,會將文件轉換為PDF檔在UI上有一個進度條顯示轉換的進度。

後來收到了一個新的需求,要在前端的操作介面增加取消下載的按鈕,使用者可以隨時按下取消下載,這時候轉檔的任務要被取消,那時候很菜用了很不好的解決方法,就是在前端當使用者按下按鈕的時候,發送一個參數到後端,在方法裡面去偵測這個參數是否為true,為true的話會直接return,至今想想真的是超級鳥的🥲,轉換的動作沒有被立即停止,只是當檔案轉換完成後終止實際上已經完成轉換的任務了,現在回想起來應該使用CancellationToken來取消一個任務。


什麼是CancellationToken?

CancellationToken這個物件是可以一層一層往下傳遞至每個作業中,告知這個作業是否要被取消

我們可以使用LINQPad的Dump將其輸出看一下有什麼屬性

優雅的使用CancellationToken取消一個任務

我們比較常使用的是IsCancellationRequested 他是一個 布林值 用來檢查取消請求是否已被觸發

在.net 的非同步方法的API中有大量地使用CancellationToken 我們以Microsoft.EntityFrameworkCore來舉例

常見的FirstOrDefaultAsync方法也有使用到喔

可以參考微軟官方的解說CancellationToken


動手實作一個小範例

我們來寫一個小範例來體驗一下怎麼使用CancellationToken 來取消一個任務

情境是當前端的使用者按下取消下載時,我們後端就會將檔案轉換PDF的任務被取消

我們先寫一個模擬檔案轉換的方法

這邊我們的方法很簡單,是模擬轉換檔案時顯示給使用者的進度條
接下來我們生成一個取消下載的Button

我們現在按下按鈕仍然沒有發生任何事情。

優雅的使用CancellationToken取消一個任務

首先我們要把轉換檔案的方法改成可以接受一個CancellationToken 參數的方法

同時在Main方法中生成一個CancellationTokenSource

CancellationTokenSource物件包含一個 CancellationToken 屬性

這個 CancellationToken 會被傳遞給非同步操作,並用於監控取消請求。

我們把CancellationTokenSource 的 Token 傳入檔案轉換的方法中

那什麼時候CancellationTokenSource的Token會被告知要取消呢?

就在我們按鈕被點下去的時候,所以我們要將Button 註冊一個Click事件

這邊使用Lambda表達式的匿名方法,來讓Click事件發生時CancellationTokenSource會觸發Cancel

接著回到我們的檔案轉換方法

增加了cts.IsCancellationRequested的判斷,也將這時候的CancellationToken列印出來

下載任務被中斷了!!

而且IsCancellationRequested變為true

這樣我們就做到了使用CancellationToken來取消一個任務了


如何變得更優雅?

實際上在專案中我們會更常使用到ThrowIfCancellationRequested()來丟出一個例外

這樣我們可以在呼叫方法時包上try catch

我們要捕捉的例外是OperationCanceledException

最後的Code是這樣,是不是又變得更優雅了呢~

Visited 49 times, 1 visit(s) today

Leave A Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *