Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task.WaitAny when there are multiple tasks that finishes at the same time

I'm using Task.WaitAny and passing in the array of tasks that are running. I would like to know how I can capture all the completed tasks' indexes, if there were multiple tasks that completes at the same time.

For instance, I'm retrieving the index of the task that completes as follows:`

int i = Task.WaitAny(taskArray);

Using the index i, I'm replacing that position in the array with another launched task. The taskArray has a fixed length and I can only launch new tasks and replace tasks in the array as they complete. How can I do this if I only get one index returned on the Task.WaitAny() and it's possible that multiple tasks within the array may complete at the same time. If only one index is returned, how do I handle other tasks that completes at the same time?

`

like image 221
ptn77 Avatar asked May 31 '17 22:05

ptn77


People also ask

Which returns a task task that completes when any of its arguments completes?

WhenAny<TResult>(Task<TResult>[]) Creates a task that will complete when any of the supplied tasks have completed.

When use Task WhenAny?

By using Task. WhenAny, you can start multiple tasks at the same time and process them one by one as they're completed rather than process them in the order in which they're started.

How to wait for 2 tasks to finish in c#?

What you are likely looking for is the method Task. WaitAll(task1, task2, task3..);. The method allows you to wait for several tasks to finish, even though the tasks execute in parallel.

How do I run a parallel task in C#?

If you have several tasks that can be run in parallel, but still need to wait for all the tasks to end, you can easily achieve this using the Task. WhenAll() method in . NET Core. This will upload the first file, then the next file.


2 Answers

If only one index is returned, how do I handle other tasks that completes at the same time?

To be clear: it is for all intents and purposes impossible that it could literally be true that more than one task would complete at the same time. Even running in separate CPU cores concurrently, the likelihood of true simultaneous completion is basically nil.

So, what you are really asking about is the race condition where one task completes, and then before your call to WaitAny() returns in your thread and the subsequent code in the calling method can execute, one or more other tasks also complete.

Your question lacks detail regarding your actual scenario, but typically you've got a couple of options:

  1. Scan the taskArray you passed to WaitAny() to look for all of the currently completed tasks.
  2. Call WaitAny() again, with all of the previously passed tasks except the one you know about.

Which is more appropriate depends on what you actually need to do with the completion information. The first option is best in cases where you only care about the currently completed tasks and want to deal with them right away. The second option is best in cases where you are interested in ordered completion result (i.e. to know which task completed in which order), but do also want to immediately continue waiting for the remainder.

Note that in the second option, if more than one task is completed before you get to call WaitAny() again, the ordering is somewhat arbitrary due to the race condition. The condition is "solved" by the WaitAny() method, with it choosing which task is presented to you as the current task that has just completed. But unless you maintain your own timing information in each task, you won't be able to know for sure which truly completed first.

If the above does not adequately address your concern, you need to improve your question, so that it includes complete details as to why the above doesn't address your concern, and exactly how you are trying to use the completion of the WaitAny() method. Make sure you include a good Minimal, Complete, and Verifiable code example that illustrates all of this.


(Aside: the above all of course ignores whether one should use WaitAny() at all. It would generally be better to asynchronously wait using WhenAny(). But the same basic issues apply, and would not change the answer, so it seems reasonable to not worry about that difference for now.)

like image 175
Peter Duniho Avatar answered Sep 30 '22 17:09

Peter Duniho


Any task can finish at any time. Sure it is possible that two ore more tasks finished at the same time.

But there is nothing you should care about in your case. Task.WhenAny will return the index of one task in the array that is completed. Place a new task at the index and call Task.WhenAny again. If there were any completed tasks in the array it will return without a delay with the index of one of the completed tasks.

async Task Execute( IEnumerable<Func<Task>> taskFunctions, int maxParallel )
{
    var taskList = new List<Task>(maxParallel);
    foreach ( var taskFunc in taskFunctions )
    {
        var task = taskFunc();
        taskList.Add( task );
        if ( taskList.Count == maxParallel )
        {
            var idx = await Task.WhenAny( taskList ).ConfigureAwait(false);
            taskList.RemoveAt( idx );
        }
    }
    await Task.WhenAll( taskList ).ConfigureAwait(false);
}
like image 26
Sir Rufo Avatar answered Sep 30 '22 17:09

Sir Rufo