Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
597 views
in Technique[技术] by (71.8m points)

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

Please, observe the following trivial code:

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

Running it outputs:

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

Note, no Timed out message.

Now, if I replace Task.WhenAny with Task.WhenAll here is what I get:

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

Note the presence of the Timed out message this time.

And, if I remove the Task.WhenAll wrapper at all and call RunAsync directly:

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

The Timed out message is there, as expected.

So what is the deal with Task.WhenAny ? It obviously interrupts the asynchronous method, but where is the TimeoutException?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Task.WhenAny doesn't rethrow exceptions from the individual tasks (unlike 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."

From Task.WhenAny

That means that it will complete successfully no matter what without any type of exceptions.

To actually rethrow the exception of the individual completed task you need to await the returned task itself:

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

Or in your case:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...