我想知道哪種方法在內存和資源使用方面會更有效率。使用任務重試異步函數 - 哪種方法更高效?
特別是在方法#1中,我很難想象如何創建任務對象並且線程開始運行?有人可以解釋一下在封面下詳細描述的內容嗎?
我想使用#1,如果兩者之間沒有區別(想避免冒泡異步)。 #2,我知道編譯器會在下面生成一個狀態機並返回。 OTOH,#1在概念上看起來是遞歸的,但它是否會像傳統意義上的遞歸一樣在一個堆棧幀中等待另一個呢?
方法1:
internal static Task ExecuteAsyncWithRetry(Func<Task> methodToExecute, Func<bool> shouldRetry)
{
var tcs = new TaskCompletionSource<object>();
try
{
return methodToExecute().ContinueWith<Task>((t) =>
{
if (t.IsFaulted || t.IsCanceled)
{
if (shouldRetry())
{
return ExecuteAsyncWithRetry(methodToExecute, shouldRetry);
}
else
{
tcs.SetException(t.Exception);
}
}
else
{
tcs.SetResult(null);
}
return tcs.Task;
}, TaskContinuationOptions.ExecuteSynchronously).Unwrap();
}
catch(Exception ex)
{
tcs.SetException(ex);
}
return tcs.Task;
}
方法#2(忽略了兩者之間的異常傳播的差異):
internal static async Task ExecuteWithRetry(Func<Task> methodToExecute, Func<bool> shouldRetry)
{
while (true)
{
try
{
await methodToExecute();
}
catch(Exception ex)
{
if(!shouldRetry())
{
throw;
}
}
}
}
第二種方法更清楚地閱讀和理解。我的經驗法則:如果可能,請使用異步等待。在你的情況下,這是可能的。但在第二種情況下,你錯過了某種終止條件。如果一切順利,'methodToExecute()' 將被重複執行。 – Krumelur
請注意,該等待會丟失錯誤信息,因爲它解開了AggregateException的錯誤信息。對於像這樣的通用輔助方法來說這是不可取的。這不是解釋例外的行爲。 – usr
謝謝@usr,但是,您能澄清一下丟失錯誤信息部分嗎?不應該等待UnWrap()的行爲並傳播內部任務的錯誤/異常? – Kakira