在C#中使用"ContinueWith"了解异步/等待与等待行为 [英] Understanding async/await vs Wait in C# with "ContinueWith" behavior

查看:66
本文介绍了在C#中使用"ContinueWith"了解异步/等待与等待行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一种方法是标准的异步方法,就像这样:

One method is a standard async method, like this one :

private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)

我已经测试了两种实现,一种使用 await ,另一种使用 .Wait()

I have tested two implementations, one that use await and the other uses .Wait()

这两个实现根本不相同,因为相同的测试在等待版本中失败了,但不是在Wait()测试中失败了.

The two implementations are not equal at all because the same tests are failing with the await version but not the Wait() one.

此方法的目标是执行由输入函数返回的Task,并通过执行相同的函数进行重试直到其起作用"(如果达到一定的尝试次数,则限制自动停止).

The goal of this method is to "execute a Task returned by the input function, and retry by executing the same function until it works" (with limitations to stop automatically if a certain number of tries is reached).

这有效:

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; 执行之前,没有等待递归调用的结果:

And this (with async t => and the usage of await instead of t => and the usage of .Wait() doesn't work at all because the result of the recursive call is not awaited before the final return; is executed :

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完成.

I'm trying to understand why this simple change does change everything, when it's supposed to do the exact same thing : waiting the ContinueWith completion.

如果我提取通过 ContinueWith 方法运行的任务,我确实会看到ContinueWith函数的状态传递给"ranToCompletion" 之前,内部等待的返回完成

If I extract the task ran by the ContinueWith method, I do see the state of the ContinueWith function passing to "ranToCompletion" before the return of the inner await completes.

为什么?不是应该等待吗?

Why? Isn't it supposed to be awaited?

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; ?

Why does var hello = o; is reached before o=10?

#1等待是否应该挂断,然后才能继续执行?

Isn't the #1 await supposed to hang on before the execution can continue?

推荐答案

lambda语法掩盖了您ContinueWith( async void ...)的事实.

The lambda syntax obscures the fact that you ContinueWith(async void ...).

异步无效方法不会被等待,并且它们抛出的任何错误都不会被观察到.

async void methods are not awaited and any errors they throw will go unobserved.

对于您的基本问题,无论如何都不建议在捕获范围内重试.太多事情发生了,捕获块应该很简单.并且直率地尝试 all 异常类型也是很可疑的.您应该知道哪些错误可以重试,然后让其他错误通过.

And to your base question, retrying from within a catch is not a recommended practice anyway. Too much going on, catch blocks should be simple. And bluntly retrying for all exception types is also very suspect. You ought to have an idea what errors could warrant a retry, and let the rest pass.

为简单起见和可读性而去:

Go for simplicity and readability:

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

   Delay();
}

这篇关于在C#中使用"ContinueWith"了解异步/等待与等待行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆