Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task.WhenAny - What happens with remaining running tasks?

I have the following code:

List<Task<bool>> tasks = tasksQuery.ToList(); while (tasks.Any()) {     Task<bool> completedTask = await Task.WhenAny(tasks);     if (await completedTask)         return true;      tasks.Remove(completedTask); } 

It launches tasks in parallel. When first completed task returns true, the method returns true.

My questions are:

  1. What happens with all remaining tasks that have been launched and probably still running in the background?
  2. Is this the right approach to execute code that is async, parallel and should return after the first condition occurs, or it is better to launch them one by one and await singularly?
like image 296
Aleksander Bethke Avatar asked Jan 02 '17 11:01

Aleksander Bethke


People also ask

How does task WhenAny work?

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. The following example uses a query to create a collection of tasks. Each task downloads the contents of a specified website.

Does task start WhenAny tasks?

As others have noted, Task. WhenAll only aggregates the tasks; it does not start them for you.


1 Answers

Incidentally, I am just reading Concurrency in C# CookBook, by Stephen Cleary, and I can refer to some parts of the book here, I guess.

From Recipe 2.5 - Discussion, we have

When the first task completes, consider whether to cancel the remaining tasks. If the other tasks are not canceled but are also never awaited, then they are abandoned. Abandoned tasks will run to completion, and their results will be ignored. Any exceptions from those abandoned tasks will also be ignored.

Another antipattern for Task.WhenAny is handling tasks as they complete. At first it seems like a reasonable approach to keep a list of tasks and remove each task from the list as it completes. The problem with this approach is that it executes in O(N^2) time, when an O(N) algorithm exists.

Besides that, I think WhenAny is surely the right approach. Just consider the following Leonid approach of passing the same CancellationToken for all tasks and cancel them after the first one returns. And even that, only if the cost of these operations is actually taxing the system.

like image 93
heltonbiker Avatar answered Sep 21 '22 01:09

heltonbiker