一种方法是标准的异步方法,就像这个:
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
我已经测试了两个实现方式,一个使用 await,另一个使用 .Wait()。
这两种实现方式完全不同,因为相同的测试在 await 版本中失败,但在 Wait() 版本中没有失败。
该方法的目标是“执行由输入函数返回的任务,并通过执行相同的函数重试直到成功”(在达到一定尝试次数后自动停止限制)。
以下代码可以运行:
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
{
try {
await taskToRun();
}
catch(Exception)
{
// Execute later, and wait the result to complete
await Task.Delay(currentDelayMs).ContinueWith(t =>
{
// Wait for the recursive call to complete
AutoRetryHandlerAsync_Worker(taskToRun).Wait();
});
// Stop
return;
}
}
使用 async t =>
以及使用 await
而不是 t =>
和 .Wait()
的方式是行不通的,因为在最后执行 return;
前,递归调用的结果没有被等待:
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
{
try {
await taskToRun();
}
catch(Exception)
{
// Execute later, and wait the result to complete
await Task.Delay(currentDelayMs).ContinueWith(async t =>
{
// Wait for the recursive call to complete
await AutoRetryHandlerAsync_Worker(taskToRun);
});
// Stop
return;
}
}
我试图理解为什么这个简单的变化会改变一切,当它应该做相同的事情:等待ContinueWith
完成。
如果我提取由ContinueWith
方法运行的任务,我会看到ContinueWith
函数的状态在内部等待返回之前就传递到了" ranToCompletion "。
为什么?难道它不应该被等待吗?
具体可测试的行为
public static void Main(string[] args)
{
long o = 0;
Task.Run(async () =>
{
// #1 await
await Task.Delay(1000).ContinueWith(async t =>
{
// #2 await
await Task.Delay(1000).ContinueWith(t2 => {
o = 10;
});
});
var hello = o;
});
Task.Delay(10000).Wait();
}
为什么在 o=10 之前就已经执行了 var hello = o;
?
#1 await 不是应该等待执行才能继续吗?
ContinueWith
方法无法处理“异步 Lambda”并且不会等待 Lambda 返回的任务完成,而是仅将该任务通过ContinueWith
返回,并让其他人来 await。如果要处理此类情况,则需要使用await await
。 - Lasse V. Karlsenwhile (true) { try { await taskToRun(); return; } catch (Exception) { await Task.Delay(currentDelayMs); } }
- Matthias247.Wait()
方法会在线程池上阻塞一个线程(Task.Delay()
在这里结束),直到taskToRun()
完成。根据并发级别和taskToRun
的持续时间,这可能不是理想的解决方案。 - Matthias247