【转】1.B(译).NET4.X并行任务Task需要释放吗?
傳送門:異步編程系列目錄……
?
摘要:本博文解釋在.NET 4.X中的Task使用完后為什么不應該調(diào)用Dispose()。并且說明.NET4.5對.NET4.0的Task對象進行的部分改進:減輕Task對WaitHandle對象的依賴,并且增強在釋放了Task后對其成員的可訪問性。
?
我多次獲得這樣一個問題:
?????????“Task實現(xiàn)了IDisposable接口并且公開Dispose()方法,這是否意味著我們要對所有的任務進行釋放嗎?”
?
概述
1.?????????這是我對該問題的簡要回答:
“不是,不用釋放你持有的Task。”
?
2.?????????這是我對該問題的中篇回答:
“不是,不用釋放你持有的Task,除非性能報告或可伸縮性測試報告顯示你需要釋放Task以滿足你的性能目標。如果你發(fā)現(xiàn)一個需要被釋放的Task,必須100%確保在你的釋放點處該Task已經(jīng)完成并且沒有被其他地方在使用。”
?
3.?????????下面,你可以找一個休閑的閱讀時間,這是我對該問題的長回答:
?
為什么要調(diào)用Task的Dispose()?
.NET Framework設計指南中指出:一個類型如果持有其它實現(xiàn)過IDisposable接口的資源時,其自身也應該實現(xiàn)IDisposable接口。在Task內(nèi)部,可能會分配一個WaitHandle對象用于等待任務完成。WaitHandle實現(xiàn)IDisposable接口因為它持有SafeWaitHandle內(nèi)核等待句柄,所以Task實現(xiàn)了IDisposable接口。如果不主動釋放SafeWaitHandle句柄,最終終結器也會將其清理,但是不能對此資源立即清理并且還將此清理工作負荷遺留給系統(tǒng)。通過給Task實現(xiàn)IDisposable接口,我們可以讓開發(fā)人員能主動及時的對資源進行釋放。
?
問題
?????????如果為每一個Task都分配一個WaitHandle,那么釋放Task將是一個好措施因為這樣能提高性能。但是事實并非如此,現(xiàn)實中,為Task分配WaitHandle的情況是非常少出現(xiàn)的。在.NET 4.0中,WaitHandle在以下幾種情況會延遲初始化:訪問?((IAsyncResult)task).AsyncWaitHandle成員,或者調(diào)用Task的WaitAll()/WaitAny()方法(這兩個方法在.NET4.0版本中,內(nèi)部是基于Task的WaitHandle對象實現(xiàn)的)。這使得回答“是否應該釋放Task”問題更加困難了,因為如果Task都使用了WaitAll()/WaitAny(),那么釋放Task就是一個好選擇。
| 1 2 3 4 5 6 7 | public?interface?IAsyncResult { ????object?AsyncState { get; } ????WaitHandle AsyncWaitHandle { get; } ????bool?CompletedSynchronously { get; } ????bool?IsCompleted { get; } } |
?????????在.NET 4.0中,一個Task一旦被釋放,它的大多數(shù)成員訪問都會拋出ObjectDisposedExceptions異常。這使得完成的任務很難被安全的緩存,因為一個消費者釋放Task后,另一個消費者無法再訪問Task的一些重要成員,如ContinueWith()方法或Result屬性。
?????????這里還有另外一個問題:Task是基礎同步基元。如果Task被用于并行化,如在一個fork/join模式(”分支/合并”模式)中那么它就很容易知道什么時候完成它們和什么時候沒有人再使用它們,比如:
| 1 2 3 4 5 6 | var?tasks = new?Task[3]; tasks[0] = Compute1Async(); tasks[1] = Compute2Async(); tasks[2] = Compute3Async(); Task.WaitAll(tasks); foreach(var?task in?tasks) task.Dispose(); |
?????????然而,當使用Task的延續(xù)任務時,就很難判斷它什么時候完成它們和什么時候沒有人再使用它們,比如:
| 1 2 3 4 5 | Compute1Async().ContinueWith(t1 => { ????t1.Dispose(); ????… }); |
示例成功的釋放掉Compute1Async()返回的Task,但是它忽略了如何釋放ContinueWith()返回的Task。當然,我們能使用同樣的方法釋放這個Task。
| 1 2 3 4 5 | Compute1Async().ContinueWith(t1 => { ????t1.Dispose(); ????… }).ContinueWith(t2 => t2.Dispose()); |
但是我們不能釋放第二個ContinueWith()返回的Task。即使使用C#5.0中新的async/await異步方法也不能解決。例如:
| 1 2 3 | string?s1 = await Compute1Async(); string?s2 = await Compute2Async(s1); string?s3 = await Compute3Async(s2); |
如果想釋放這些Task,我需要進行像下面這樣的重寫:
| 1 2 3 4 5 6 7 | string?s1 = null, s2 = null, s3 = null; using(var?t1 = Compute1Async()) ????s1 = await t1; using(var?t2 = Compute2Async(s1)) ????s2 = await t2; using(var?t3 = Compute3Async(s2)) ????s3 = await t3; |
?
解決方案
?????????由于像上面這樣進行釋放大多數(shù)Task顯得很繁瑣,所以在.NET4.5中已經(jīng)對Task的Dispose()做過一些改進:
1.?我們使得你更少機會為Task創(chuàng)建WaitHandle對象。在.NET4.5中我們已經(jīng)重寫了Task的WaitAll()和WaitAny()以致這兩個方法不再依賴與WaitHandle對象(這樣WaitAll()、WaitAny()、Wait()就都基于自旋等待),避免在Task的內(nèi)部實現(xiàn)中使用WaitHandle對象,并且提供async/await相關異步功能。因此,只有當你顯示訪問Task的IAsyncResult.AsyncWaitHandle成員才會為Task分配WaitHandle對象,但這種需求非常少見。這意味著除了這種非常少見的情況外,釋放一個任務是不需要的。
2.??????我們使得Task在釋放后依然可用。你能使用Task的所有公開成員即使Task已經(jīng)被釋放,訪問這些成員的表現(xiàn)就和釋放Task之前一樣。只有IAsyncResult.AsyncWaitHandle成員你不能使用,因為這是你釋放Task時真真所釋放的對象,當你嘗試在釋放Task后訪問這個屬性時依然會拋出ObjectDisposedException。此外,更進一步的說,現(xiàn)在我們推薦使用async/await異步方法以及基于任務的異步編程模式,降低對IAsyncResult的使用,即使你繼續(xù)使用((IAsyncResult)task),調(diào)用其AsyncWaitHandle成員也是十分罕見的。
3.?????????Task.Dispose()方法在“.NET Metro風格應用程序”框架所引用的程序集中甚至并不存在(即此框架中Task沒有實現(xiàn)IDisposable接口)。
?
指南
所以,這又讓我們回到了簡要的回答:“不是,不用釋放你的Task。”通常很難找到一個合適的釋放點,目前幾乎沒有一個理由需要去主動釋放Task(因為調(diào)用((IAsyncResult)task).AsyncWaitHandle成員的需求是十分罕見的),并且在“.NET Metro風格應用程序”框架所引用的程序集中你甚至不能調(diào)用Task的Dispose()方法。?
???????????????????
?
更多資源來源博文:關于Async與Await的FAQ
?
?
原文:http://blogs.msdn.com/b/pfxteam/archive/2012/03/25/10287435.aspx
作者:Stephen Toub - MSFT
?
?
作者:滴答的雨
出處:http://www.cnblogs.com/heyuquan/
本文版權歸作者和博客園共有,歡迎轉載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
總結
以上是生活随笔為你收集整理的【转】1.B(译).NET4.X并行任务Task需要释放吗?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 海王娘娘否认剧情杀
- 下一篇: 【转】C#中枚举类型与静态变量