繁体   English   中英

了解async / await vs在C#中使用“ContinueWith”行为等待

[英]Understanding async/await vs Wait in C# with “ContinueWith” behavior

一种方法是标准的异步方法,如下所示:

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;之前不等待递归调用的结果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函数的状态在内部await返回完成之前传递给“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();
}

为什么var hello = o; 在o = 10之前达到?

在执行可以继续之前,是不是#1等待应该挂起?

lambda语法模糊了ContinueWith( async void ...)的事实。

不等待async void方法,它们抛出的任何错误都将被忽略。

对于你的基本问题,无论如何,从捕获内重试都不是推荐的做法。 太多了,抓住块应该很简单。 并且直截了当地重试所有异常类型也是非常可疑的。 你应该知道哪些错误可以保证重试,其余的通过。

简单易懂:

while (count++ < N)
{
   try
   {          
      MainAction();
      break;      
   }
   catch(MoreSpecificException ex) { /* Log or Ignore */ }

   Delay();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM