# 使用 LINQPad 進行長時間的非同步事件該如何安全的取消執行

我現在幾乎所有的 Side Projects 都是用 LINQPad 開發的，不用管理什麼方案或專案，也不用想什麼各種詭異的架構，想到什麼功能就直接寫出來，搭配 AI 助理更是如虎添翼。最近我的一個小小的 AI 專案由於執行時間長，且 AI 回應速度慢又不穩定，因此我加入了快取功能，但是程式只要手動停止，執行中所建立的快取就會失效，所以有點小困擾。今天這篇文章我要介紹一個 LINQPad 8.1 的新功能，還有分享如何「優雅的結束」程式執行。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/84bb459b51ef0e896034-8ff10bc2-0ac7-4ff7-a0d6-ea41020ad3c3.webp)

### 問題描述

先看一下我的程式碼：

```csharp
translatedText = await Translate(text);
```

這段程式是我自己寫好的一個非同步方法，他會透過 Gemini 1.0 Pro 的 API 來翻譯文字，但是這個方法的執行時間有時候會很長，所以我加入了快取功能，程式碼改寫如下：

```csharp
translatedText = await Util.CacheAsync(async () => await Translate(text), "v1:" + text);
```

這裡的 `Util.CacheAsync()` 方法是 LINQPad 8.1 新增的一個工具方法，當然也只能在 LINQPad 使用，它可以讓你用 `await` 的方式等待程式執行的結果，並且將結果快取起來。其中 `"v1:" + text` 這段只是一個 `cache key` 而已，下一次執行時，如果從記憶體中有找到相同的 `cache key` 就會直接回傳結果，因此程式的執行效率將會大大提升！👍

當我想要提前結束程式時，我會按下 `Shift+F5` 快速鍵來停止，不過 LINQPad 在預設的情形下，會用強制 Kill Process 的方式停止，而這個過程將會導致程式執行過程中的「快取資料」遺失。這個行為對我就會造成困擾，因為我的程式會執行很久，很多理論上已經快取的資料，下次我並不想再次執行，應該讀取快取材對。

### 解決方案

在我[詢問 LINQPad 作者](https://forum.linqpad.net/discussion/3110/util-cache-seems-not-cache-things-when-query-canceled-before-it-finish#latest)之後，他告訴我 LINQPad 本身就內建了 `Soft-Cancel` 機制，只要你在程式中加入以下程式碼，就可以在按下 `Shift+F5` 時，讓程式可以「優雅的結束」：

```csharp
if (QueryCancelToken.IsCancellationRequested) return;
```

簡單來說，只要 LINQPad 查詢可以正常的結束，基本上就可以保留下所有快取過的資料！

基本上只要你的 LINQPad 查詢中有用到 `QueryCancelToken` 這個類別，LINQPad 就會自動啟用這個 `Soft-Cancel` 機制，你的 LINQPad UI 也會有點小改變。如下圖所示，你在 LINQPad 查詢中加入程式碼之後，執行時若要停止程式，原本的 `Cancel` 按鈕，現在會變成停用 `Soft-Cancel` 的按鈕：

![LINQPad Soft-Cancel](https://stwillblogassets.blob.core.windows.net/files/images/external/github.com/cf44f87f06f6736b70f0-c214a03c-853b-4810-a5ee-b7d0b3ca4610.png)

這時候你按下 `Shift+F5` 就不會直接結束程式，而是提供你一個 [CancellationToken](https://learn.microsoft.com/zh-tw/dotnet/api/system.threading.cancellationtoken?view=net-8.0&WT.mc_id=DT-MVP-4015686) 讓你可以在程式中判斷何時該結束、該怎樣結束等等，簡單來說，就是不會直接結束你的程式，你的程式要自行處理結束的邏輯，也因此這就是「優雅的結束」的意思。

### 總結

這個設計真的很漂亮，我可以非常放心的將程式執行結果快取起來，不用擔心程式被強制結束時，快取資料會遺失。👍

如果你想查詢更多 **Soft cancellation** 的相關資訊，可以在 LINQPad 軟體中，先點擊主選單的 `Help` > `Help on LINQPad - Search` 或輸入鍵盤快速鍵 `Ctrl+F1`，接著輸入 `cancellation` 就可以快速查到範例程式可供參考。

### 相關連結

-   [LINQPad Release Notes](https://www.linqpad.net/LINQPad8.aspx#:~:text=also%20new%20a-,Util.CacheAsync,-method%20to%20cache)
-   [LINQPad Forum](https://forum.linqpad.net/)
    -   [Util.Cache seems not cache things when Query canceled before it finish](https://forum.linqpad.net/discussion/3110/util-cache-seems-not-cache-things-when-query-canceled-before-it-finish#latest)
