對于我的專案中的一些重快取/高性能路徑,我需要將 a “轉換”Task<X>為Task<Y>型別 -請參見此處。
我使用了該ContinueWith解決方案,但我注意到即使我的原始任務處于某種RanToCompletion狀態,ContinueWith仍然回傳 a Taskthat is WaitingToRun。
var task = Task.FromResult("cheese");
var test = task.ContinueWith(x => (object)x);
Console.WriteLine(test.Status); // WaitingToRun
Console.ReadLine();
由于超出此問題范圍的原因,這給了我一些額外的成本。
如果我執行以下操作,我的非常具體的問題似乎得到了解決,它將直接回傳一個 CompletedTask,否則它會執行正常邏輯。
if ( task.IsCompletedSuccessfully )
return Task.FromResult((object)task.Result);
else
return task.ContinueWith(x => (object)x);
將這條“快樂之路”添加到我的邏輯中是否安全?
因為這條路徑不在正常ContinueWith邏輯中,所以我擔心我遺漏了一些東西,當在高并發環境中運行時,這會咬我。
uj5u.com熱心網友回復:
就像幾乎任何時候出現的情況一樣ContinueWith,答案是await改用。正確使用ContinueWith真的很難,而且它幾乎從來都不是任何給定問題的最有效解決方案。
你發現了一個問題ContinueWith,即沒有真正小心你的調度程式(或手動檢查任務是否完成),你最終會強制將作業安排到執行緒池執行緒中,以便稍后運行'不需要。(這不會總是發生,所以你不能依賴這種行為,但這是可能的,坦率地說,更糟。)
此外,您的ContinueWith代碼無法正確處理錯誤/取消。在您的代碼中,取消的任務反而會出錯,而出錯的任務會將其例外包裝在 AggregateException 中。
您的代碼還有一個錯誤,即您在強制轉換之前沒有從任務中獲取結果,因此您的任務的結果是另一個強制轉換為物件的任務,但只需添加Result呼叫即可輕松修復該部分。
這是一個嘗試解決這些問題的 pre-await 解決方案,但在 post-await 世??界中,沒有必要。
public static async Task<TResult> Cast<TSource, TResult>(
this Task<TSource> task)
{
return (TResult)(object) await task.ConfigureAwait(false);
}
不僅是await調度延續的更有效的語法,而且它的默認行為在任何給定情況下都比ContinueWith. 它會檢查任務是否已完成,如果未完成,則僅安排后續運行,它不會將例外包裝在 AggregateException 中,等等。我們不想要的唯一默認行為是默認情況下await維護當前同步背景關系,這通常是正確的,但我們的方法恰好不需要這里。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/513478.html
標籤:C#异步任务
