.NET 4.5任務并行庫改動與指南

fmms 12年前發布 | 6K 次閱讀 .NET

在 .NET 4.0 中,Task 類暴露了 IDisposable 接口。Task 可被回收(disposable)是為了清理 IAsyncResult 接口中 AsyncWaitHandle 屬性暴露的等待句柄(wait handle)。在 .NET 4.0 中,等待句柄只有在讀取 AsyncWaitHandle 屬性,或者使用 Task.WaitAll、Task.WaitAny 時才會被創建,其他情況調用 Task.Dispose 都是多余的。

遺憾的是,.NET 4.0 中的 Task 在處理 ObjectDisposedException 時顯得過于武斷:一旦調用 Dispose 釋放等待句柄之后,即使其他屬性與之毫無聯系,剩余對象也會變得不穩定。

那么在 .NET 4.0 中是否應該調用 Task.Dispose?

不應該,除非遇到以下情況:

  1. 整個 Task 不會被緩存;
  2. 等待句柄是通過調用 Task.WaitAll、Task.WaitAny,或是讀取 IAsyncResult.AsyncWaitHandle 創建而成;
  3. Task 上沒有其他任務或線程處于等待狀態。

其實,即使所有的條件都滿足,你也不用做什么,因為終結器 (finalizer)在清理等待句柄方面已經做了相同高效的工作。所以,除非你看到一些性能問題,否則你也許可以仍然不用回收 task。

.NET 4.5 核心中的改動

在 .NET 4.5 中,只有顯式讀取 IAsyncResult.AsyncWaitHandle 時,內部等待句柄才會被創建。其他部分,包括 Task.WaitAll 和 Task.WaitAny 都進行了重新設計,它們不再需要等待句柄。另外,隨著語言中對 async/await 的支持,IAsyncResult 在大部分場景中甚至都不再需要。

.NET 4.5 中 Task 的另外一個改動是 task 在釋放之后仍然可用。按照 Stephen Toub 的說法, “現在,即使 Task 釋放之后也可以使用它的所有公開成員,并且它們使用起來就和釋放之前一樣。唯一一個不能使用的成員是 IAsyncResult.AsyncWaitHandle,因為它是 Task 實例真正釋放的部分。如果試圖在 Task 釋放后訪問該屬性,它會拋出一個 ObjectDisposedException 異常。”

雖然在 .NET 4.5 中調用 Task.Dispose 變得更加安全,但是幾乎沒有理由需要這么做。

針對 .NET 4.5 Metro 的特殊規則

Stephen Toub 接著提到 Task.Dispose 在“.NET Metro 風格應用程序”框架中甚至并不存在。要注意的是,目前關于此項設計變更的信息還未在 WinRT 的 Task 文檔中更新反映。

從函數返回 Task

在另外一篇題為“是否應當為同步方法暴露異步包裝?“的文章中,Stephen 深度探討了從函數返回 Task 對象的話題。我們推薦你閱讀全篇文章,而如果你時間不充裕,可以閱讀以下的總結部分:

我認為只有那些異步方法比對應的同步方法擁有可擴展性(scalability)優勢時才應當被暴露。異步方法不應當為了單純地減輕負載(offloading)而進行暴露,因為這類優勢可以通過使用專門用于異步執行同步方法的功能輕松實現,如使用 Task.Run。

查看英文原文:Changes and Guidance for the Task Parallel Library in .NET 4.5來自: InfoQ

 本文由用戶 fmms 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!