简体   繁体   中英

Why does Task.WhenAny() not working as expected

I'm trying to implement a timeout pattern for an awaitable task as described here: https://stackoverflow.com/a/11191070

However, I am getting unexpected results. I've written a small console app to demonstrate (bottom of this post). These are the scenarios and results I get:

Scenario 1
DelayTask  Thread.Sleep(10000);
ActualTask Thread.Sleep(100);
Invoked with await Task.WhenAny(...
Result: THEN clause invoked  CORRECT

Scenario 2
DelayTask  Thread.Sleep(100);
ActualTask Thread.Sleep(10000);
Invoked with await Task.WhenAny(...
Result: THEN clause invoked  INCORRECT

Scenario 3
DelayTask  Thread.Sleep(10000);
ActualTask Thread.Sleep(100);
Invoked WITHOUT await: Task.WhenAny(...
Result: ELSE clause invoked  INCORRECT

Scenario 4
DelayTask  Thread.Sleep(100);
ActualTask Thread.Sleep(10000);
Invoked WITHOUT await: Task.WhenAny(...
Result: ELSE clause invoked  CORRECT

Can anyone shed any light as to why this is not functioning as expected. TIA!

   class Program
    {

        static void Main(string[] args)
        {
            Run();
        }

        private static async void   Run()
        {
            var _cancelWorkTokenSource = new CancellationTokenSource();
            var task = ActualTask(_cancelWorkTokenSource.Token);
            var delayTask = DelayTask(_cancelWorkTokenSource.Token);

            if (await Task.WhenAny(task, delayTask) == task)
            {
                Console.WriteLine("Task Succeeded in time."); 
            }
            else
            {
                Console.WriteLine("Task exceeded time limit");
            };

            Console.ReadLine();
        }

        private static async Task DelayTask(CancellationToken cancelToken)
        {
            Thread.Sleep(10000);
        }

        private static async Task ActualTask(CancellationToken cancelToken)
        {
            Thread.Sleep(100);
        }
    }

Because your dummy methods are implemented incorrectly. Change Thread.Sleep to await Task.Delay :

private static async Task DelayTask(CancellationToken cancelToken)
{
    await Task.Delay(10000);
}

 private static async Task ActualTask(CancellationToken cancelToken)
 {
    await Task.Delay(100);
 }

What is happening right now in your code:

  1. var task = ActualTask(_cancelWorkTokenSource.Token) blocks current thread for 10000 milliseconds and returns completed Task
  2. After that var delayTask = DelayTask(_cancelWorkTokenSource.Token); blocks current thread for 100 milliseconds and returns completed task
  3. await Task.WhenAny(task, delayTask) selects first of them cause both are completed

Add to your code Console.WriteLine(task.IsCompleted); and Console.WriteLine(delayTask.IsCompleted); after corresponding variables initialization to check it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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