The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

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

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

問題描述

先看一下我的程式碼:

translatedText = await Translate(text);

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

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 作者之後,他告訴我 LINQPad 本身就內建了 Soft-Cancel 機制,只要你在程式中加入以下程式碼,就可以在按下 Shift+F5 時,讓程式可以「優雅的結束」:

if (QueryCancelToken.IsCancellationRequested) return;

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

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

LINQPad Soft-Cancel

這時候你按下 Shift+F5 就不會直接結束程式,而是提供你一個 CancellationToken 讓你可以在程式中判斷何時該結束、該怎樣結束等等,簡單來說,就是不會直接結束你的程式,你的程式要自行處理結束的邏輯,也因此這就是「優雅的結束」的意思。

總結

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

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

相關連結

留言評論