[個人筆記] 例外狀況處理 (工作平行程式庫TPL)

[個人筆記] 例外狀況處理 (工作平行程式庫TPL)

[前言]

多執行緒/非同步作業向來是一個複雜但是重要的議題,目前維護的系統由於是定時執行多種排程工作,在原本的同步作業設計下的系統有些問題會意外發生,故對這個議題有興趣並進行一些研究與開發,首先一些觀念性文章我是參考Huan-Lin學習筆記

有些個人覺得重要的觀念:

按照 Damian Edwards 的看法,在 ASP.NET web 應用程式中,只有三種情況才應該使用非同步處理,而且只有第一種情況最常用,另外兩種情況則很少用到。

第一種情況、也是最常見的情況,就是 I/O 處理,包括檔案存取、網路通訊、資料庫存取(通常包含檔案和網路)等等。比如說,常見的 web service 呼叫就是屬於網路 I/O。所以,可別以為在 ASP.NET web 應用程式中就不需要使用非同步呼叫喔。

第二種情況是類似儀錶板(dashboard)之類的頁面,它需要一次呈現許多區塊,而各區塊的內容又是透過其他檔案或遠端網路呼叫的方式取得。針對這種情況,由於一次要在網頁上呈現許多不同來源的資料,與其等到所有區塊的內容都取得之後才顯示整個頁面,不如以非同步的方式分頭進行,哪個區塊先取到資料,就先顯示那個區塊的內容。

第三種情況則是需要長時間處理的 HTTP 請求。比如說,收到某個 HTTP 請求時,必須啟動一個長時間的工作,並且等待那件工作執行完畢,才將工作的結果傳回用戶端(等待過程中,HTTP 連線仍是持續開著的)。

– .NET 1.0:專屬執行緒(Thread 類別)、執行緒集區(ThreadPool 類別)。

– .NET 1.1:APM(Asynchronous Programming Model)。 .NET 非同步 API 概覽 32

– .NET 2.0:EAP(Event-based Asynchronous Pattern)。

– .NET 3.5:改進執行緒集區的效能。

– .NET 4.0:TPL(Task Parallel Library)。

– .NET 4.5:TAP(Task-based Asynchronous Pattern),C# 5 的 async 與 await 寫法。

[正文]

在導入.NET 4.0 Task(主要參考這篇)取代自己前一版使用Thread的開發方法之後,經過一段時間的穩定執行,發生了不明的錯誤訊息,而程式就卡住不動了:

A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.

找到的處理方法如,個人翻譯如下:

如果建立了一個任務,但你未曾呼叫過task.Wait()或者嘗試檢索Task<T>的結果,當task被gabage collector回收時,它將在finalization階段弄倒你的應用程式,更多的細節可以參考MSDN關於TPL例外處理的文章

最好的選擇就是"處理"異常,可以透過接續(延續?原文是continuation)來完成 - 附加一個接續到任務(task)上並且記錄或者處理其所發生的異常,這提供了一個乾淨的方式來記錄任務(task)異常,並且可以簡單地被寫成一個擴展方法:

 

public static void LogExceptions(this Task task)
{
    task.ContinueWith( t =>
    {
            var aggException = t.Exception.Flatten();
            foreach(var exception in aggException.InnerExceptions)
                LogException(exception);
    }, 
    TaskContinuationOptions.OnlyOnFaulted);
}

透過上面的擴充方法,可以用這樣的方式擴展到任務(task)中以避免程式被弄垮:

Task.Factory.StartNew( () => 
    { 
        // Do your work...
    }).LogExceptions();
}

目前這方法成功地解決了我的問題:)

 

若有謬誤,煩請告知指教,菜鳥發帖請多包涵~

 

其他參考資料:

例外狀況處理 (工作平行程式庫)

What is difference between Task and Thread?