为什么Task.WhenAny没有抛出预期的TimeoutException?

mar*_*ark 12 .net c# task-parallel-library system.reactive async-await

请遵守以下简单的代码:

class Program
{
    static void Main()
    {
        var sw = new Stopwatch();
        sw.Start();
        try
        {
            Task.WhenAny(RunAsync()).GetAwaiter().GetResult();
        }
        catch (TimeoutException)
        {
            Console.WriteLine("Timed out");
        }
        Console.WriteLine("Elapsed: " + sw.Elapsed);
        Console.WriteLine("Press Enter to exit");
        Console.ReadLine();
    }

    private static async Task RunAsync()
    {
        await Observable.StartAsync(async ct =>
        {
            for (int i = 0; i < 10; ++i)
            {
                await Task.Delay(500, ct);
                Console.WriteLine("Inside " + i);
            }
            return Unit.Default;
        }).Timeout(TimeSpan.FromMilliseconds(1000));
    }
}
Run Code Online (Sandbox Code Playgroud)

运行它输出:

Inside 0
Inside 1
Elapsed: 00:00:01.1723818
Press Enter to exit
Run Code Online (Sandbox Code Playgroud)

注意,没有超时消息.

现在,如果我更换Task.WhenAnyTask.WhenAll这里是我得到:

Inside 0
Inside 1
Timed out
Elapsed: 00:00:01.1362188
Press Enter to exit
Run Code Online (Sandbox Code Playgroud)

请注意这次出现Timed out消息.

并且,如果我删除Task.WhenAll包装器并RunAsync直接调用:

Inside 0
Inside 1
Timed out
Elapsed: 00:00:01.1267617
Press Enter to exit
Run Code Online (Sandbox Code Playgroud)

超时消息是存在的,符合市场预期.

那么交易是Task.WhenAny什么?它显然会中断异步方法,但是在哪里TimeoutException

i3a*_*non 30

Task.WhenAny不会从单个任务中重新抛出异常(与此不同Task.WhenAll):

"当任何提供的任务完成时,返回的任务将完成.返回的任务将始终RanToCompletionResult设置为第一个任务的状态结束.即使第一个完成的任务以CanceledFaulted状态结束,也是如此. "

Task.WhenAny

这意味着无论没有任何类型的例外,它都将成功完成.

要实际重新抛出单个已完成任务的例外,您需要await返回的任务本身:

var completedTask = await Task.WhenAny(tasks); // no exception
await completedTask; // possible exception
Run Code Online (Sandbox Code Playgroud)

或者在你的情况下:

Task.WhenAny(RunAsync()).GetAwaiter().GetResult().GetAwaiter().GetResult();
Run Code Online (Sandbox Code Playgroud)

  • @mark外部任务就在那里你可以等待它.内部任务是让你获得第一个完成的任务作为结果.当你使用`Task.WhenAny`时,你可能想知道哪个任务先完成,或者结果是什么. (3认同)
  • 这是否意味着您可以合法地编写 `await wait Task.WhenAny(tasks)` @i3arnon ?! (3认同)
  • 请注意,虽然您可以合法地编写“await wait Task.WhenAny(tasks)”,但只有第一个任务的结果/状态才会以这种方式进行检查。 (3认同)