简体   繁体   中英

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

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:

  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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM