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

Why does the Task.WhenAny not throw an expected TimeoutException?

请注意以下简单代码:

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));
    }
}

运行 它输出:

Inside 0
Inside 1
Elapsed: 00:00:01.1723818
Press Enter to exit

注意,没有超时消息。

现在,如果我将 Task.WhenAny 替换为 Task.WhenAll,这就是我得到的结果:

Inside 0
Inside 1
Timed out
Elapsed: 00:00:01.1362188
Press Enter to exit

注意这次 Timed out 消息的存在。

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

Inside 0
Inside 1
Timed out
Elapsed: 00:00:01.1267617
Press Enter to exit

正如预期的那样,超时 消息出现了。

那么 Task.WhenAny 是怎么回事?明明打断了异步方法,可是TimeoutException?

在哪里

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

"The returned task will complete when any of the supplied tasks has completed. The returned task will always end in the RanToCompletion state with its Result set to the first task to complete. This is true even if the first task to complete ended in the Canceled or Faulted state."

来自Task.WhenAny

这意味着它无论如何都会成功完成,没有任何类型的异常。

要真正重新抛出单个已完成任务的异常,您需要 await 返回的任务本身:

var completedTask = await Task.WhenAny(tasks); // no exception
await completedTask; // possible exception

或者您的情况:

Task.WhenAny(RunAsync()).GetAwaiter().GetResult().GetAwaiter().GetResult();