Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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 Tasks.

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:

  1. 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?
  2. Is how I am using the cancellation token look correct?
  3. 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.

like image 602
deadlydog Avatar asked Oct 16 '16 07:10

deadlydog


People also ask

Which method provides a convenient way to run any number of arbitrary statements concurrently?

Invoke method provides a convenient way to run any number of arbitrary statements concurrently. Just pass in an Action delegate for each item of work. The easiest way to create these delegates is to use lambda expressions. The lambda expression can either call a named method or provide the code inline.

How to create New Task c#?

To start a task in C#, follow any of the below given ways. Use a delegate to start a task. Task t = new Task(delegate { PrintMessage(); }); t. Start();

How Task works in c#?

A Task represents some asynchronous operation and is part of the Task Parallel Library, a set of APIs for running tasks asynchronously and in parallel. The task can return a result. There is no direct mechanism to return the result from a thread. Task supports cancellation through the use of cancellation tokens.

What is Task WhenAll?

WhenAll method is used to create a task that will complete if and only if all the other tasks have completed. If we are using Task. WhenAll we will get a task object that isn't complete. However, it will not block but will allow the program to execute.


1 Answers

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.

like image 167
usr Avatar answered Sep 25 '22 16:09

usr