What is the best way to start thousands of Tasks in C#

c#, multithreading, task-parallel-library

Solution

Yes, this code would start all operations at once. The `Task.Run` does not do much. Since this is using async IO the thread pool has little involvement. It will not throttle this.

Don't do this. Likely, this will overload some resource. Use the last piece of code from https://blogs.msdn.microsoft.com/pfxteam/2012/03/05/implementing-a-simple-foreachasync-part-2/. Such a thing should be in the framework because almost always is it necessary to pick an exact degree of parallelism for IO work.

(3) does not matter after the fix is applied. Before the fix the token has almost no impact because all operations are started immediately causing the token to be checked only once immediately. After that cancellation is no longer possible.

You can also pass the token to `UpdateUserInExternalService` to achieve even more immediate cancellation.

Problem

Lets say I have a `List` of users, and I want to perform some operation on all of them, such as updating one of their properties in a database. The list of users can potentially contain tens or hundreds of thousands of users. If all of the work to be done to the users was local to my machine, then I would just use `Parallel.ForEach` to process them, but because this will involve waiting (potentially many seconds) for a call to an external service to complete, I think it's more appropriate to use `Task`s. Right now, this is the code that I have: ``` Task.WaitAll(usersList.Select(user => Task.Run(() => async { cancellationToken.ThrowIfCancellationRequested(); try { await UpdateUserInExternalService(user); } catch (Exception ex) { LogError($"Something went wrong with user 'user.Username'.", ex); } }, cancellationToken)).ToArray()); ``` I have some questions: - If the list has 10,000 users in it, does it actually create 10,000 tasks all at once (huge memory spike)? Or does it just create, say 10, and then as some tasks complete the others are spun up? - Is how I am using the cancellation token look correct? - If I cancel the operation right away after invoking it, does it still have to spin up all 10,000 tasks before they are cancelled, or is that avoided because I am passing the cancellation token into the Task.Run parameters? In my testing it seems to work well. I just want to make sure there isn't anything I'm overlooking or some gotcha that I am likely to encounter, or if there's a best-practice that I'm not following. I'm open to any suggestions. Thanks in advance. Update As per the comments, I do not have any control over the external service or its database. I only have the call they provide to me, which takes a single user. Thanks.

Original source