Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine which tasks completed first using Task.WaitAny()?

In this code, you always get the same results. I don't know why the IDs of these tasks are 1,3,4.

If you put a breakpoint at int index = Task.WaitAny(tasks); and wait for 2 seconds, you get good results. The results in the first case are different and the IDs are equal to 1, 2, 3.

public class Example
{
    public static void Main()
    {
        var tasks = new Task[3];
        var rnd = new Random();
        for (int ctr = 0; ctr <= 2; ctr++)
            tasks[ctr] = Task.Run( () => Thread.Sleep(rnd.Next(500, 3000)));

        try 
        {
            int index = Task.WaitAny(tasks);
            Console.WriteLine("Task #{0} completed first.\n", tasks[index].Id);
            Console.WriteLine("Status of all tasks:");

            foreach (var t in tasks)
                Console.WriteLine("   Task #{0}: {1}", t.Id, t.Status);
        }
        catch (AggregateException) 
        {
            Console.WriteLine("An exception occurred.");
        }
    }
}

// The example displays output like the following:
//     Task #1 completed first.
//     
//     Status of all tasks:
//        Task #3: Running
//        Task #1: RanToCompletion
//        Task #4: Running
like image 931
mdlejtecole Avatar asked Sep 15 '26 02:09

mdlejtecole


1 Answers

If you look at the documentation of Task.Id, it says:

Task IDs are assigned on-demand and do not necessarily represent the order in which task instances are created. Note that although collisions are very rare, task identifiers are not guaranteed to be unique.

(emphasis mine)

So, using Task.Id for this purpose (i.e., checking what task is completed first) is in no way reliable. What you should do is rely on the index of the element in the array instead. In this case, your code would look something like this:

var tasks = new Task[3];
var rnd = new Random();
for (int ctr = 0; ctr <= 2; ctr++)
    tasks[ctr] = Task.Run(() => Thread.Sleep(rnd.Next(500, 3000)));

try
{
    int index = Task.WaitAny(tasks);
    Console.WriteLine("Task #{0} completed first.\n", (index + 1));
    Console.WriteLine("Status of all tasks:");

    for (int i = 0; i <= 2; i++)
        Console.WriteLine("   Task #{0}: {1}", (i + 1), tasks[i].Status);
}
catch (AggregateException)
{
    Console.WriteLine("An exception occurred.");
}

That way, you get different results when you run the program multiple times. You can try it online.

For more information about the behavior of Task.Id, you may read Stephen Cleary's article: A Few Words on Task.Id (and TaskScheduler.Id).

like image 84
41686d6564 stands w. Palestine Avatar answered Sep 17 '26 15:09

41686d6564 stands w. Palestine