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:
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.
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.
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.
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();
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With