There’s no need to use Parallel class for asynchronous calls. Instead don’t await on individual tasks, rather do a WhenAll or WhenAny as others have pointed it out. Or with net 9 there is a WhenEach variant allowing asynchronous await on all the tasks in any order they complete. The reason for not using Parallel class is due to the implementation difference between I/O bound and CPU bound threads. Asynchronous operations are implemented via a thread pool taking into account the fact the COU is mostly unused for the duration of the call. CPU bound work is done on parallel threads mapped directly to the logical CPU cores.
I can count on one hand the times I have used List.ForEach in C# and I've used it for more than 10 years. Your example "fetchFromDatabase" would in practice be written by passing the list of ids in and batch requesting .where(contains) (or whatever db fetch strategy is optimal), which gives you the option of using IAsyncEnumerable, the way it's written you're making N calls to the database
If you have DB requests in a loop then you are doing something wrong in your life. Otherwise it is "parallel" by itself due to different task from different clients will be scheduled on different threads due to thread pool.
@@Riketta "So, making database requests in a loop means you're 'doing something wrong in your life'? What kind of dumb comment is that? I asked this question on purpose because not all tasks can be efficiently parallelized, especially with a DbContext that isn’t thread-safe. Forcing a Parallel.ForEach where it doesn’t apply can cause more issues than it solves. And just to remind you, this video is aimed at beginners. You could have just pointed out that for read operations, it's possible to parallelize if you're accessing different tables or if you're registering the DbContext as transient, instead of jumping to useless judgments.
You should be able to do a WhenAll and Select, then an OrderBy on the whole thing. Something like this: var numbers = new List { 1, 2, 3, 4 }; (await Task.WhenAll(numbers.Select(async (n, index) => { await Task.Delay(250); return new { Index = index, Value = n }; }))) .OrderBy(result => result.Index) .ToList() .ForEach(result => Console.WriteLine(result.Value));
But why would anyone do that? void Action ... signature does no equal to Task Action. List.ForeEach was never meant to be (ab)used with "void async" signature of anonymous lamda actions.
Sorry, but I do not think you are comparing the same thing. The reason the list.foreach(async...) code did not return anything is because the program terminated right away. If you add a console.ReadLine() at the end, this will allow the tasks created in the loop to do their thing and should display the results.
Why not use .Select and Task.WaitAll?
There’s no need to use Parallel class for asynchronous calls. Instead don’t await on individual tasks, rather do a WhenAll or WhenAny as others have pointed it out. Or with net 9 there is a WhenEach variant allowing asynchronous await on all the tasks in any order they complete. The reason for not using Parallel class is due to the implementation difference between
I/O bound and CPU bound threads. Asynchronous operations are implemented via a thread pool taking into account the fact the COU is mostly unused for the duration of the call. CPU bound work is done on parallel threads mapped directly to the logical CPU cores.
i encountered this problem exactly when you posted this video, thanks very much !!!
you are very lucky bro... chat gpt learned from this guy hahaha
I can count on one hand the times I have used List.ForEach in C# and I've used it for more than 10 years.
Your example "fetchFromDatabase" would in practice be written by passing the list of ids in and batch requesting .where(contains) (or whatever db fetch strategy is optimal), which gives you the option of using IAsyncEnumerable, the way it's written you're making N calls to the database
i use it quite extensively for I/O workloads (files downloads in parrallel) it's actually really useful to avoid boilerplate
Great content as always.
Thx a lot for your video ,
Can you use parallel if you call a repository with a dbcontext ?
If you have DB requests in a loop then you are doing something wrong in your life.
Otherwise it is "parallel" by itself due to different task from different clients will be scheduled on different threads due to thread pool.
You can for multi reads. For multi writes also but make sure its under transaction scope
DbContext is not thread safe so you'd need to instantiate a new context for each operation.
@@Riketta "So, making database requests in a loop means you're 'doing something wrong in your life'? What kind of dumb comment is that? I asked this question on purpose because not all tasks can be efficiently parallelized, especially with a DbContext that isn’t thread-safe. Forcing a Parallel.ForEach where it doesn’t apply can cause more issues than it solves. And just to remind you, this video is aimed at beginners. You could have just pointed out that for read operations, it's possible to parallelize if you're accessing different tables or if you're registering the DbContext as transient, instead of jumping to useless judgments.
@@padnom4991 you are right, if in your reality loops more often than almost never used to complete actions like "accessing different tables".
what if we want to send multiple HttpClient requests
Could you create a video about using Radzen within MAUI Blazor?
You should probably be using ConcurrentBag for your last example. I know it's a bit out of scope but just be correct. Other than that, great video!
You should be able to do a WhenAll and Select, then an OrderBy on the whole thing. Something like this:
var numbers = new List { 1, 2, 3, 4 };
(await Task.WhenAll(numbers.Select(async (n, index) =>
{
await Task.Delay(250);
return new { Index = index, Value = n };
})))
.OrderBy(result => result.Index)
.ToList()
.ForEach(result => Console.WriteLine(result.Value));
But why would anyone do that? void Action ... signature does no equal to Task Action. List.ForeEach was never meant to be (ab)used with "void async" signature of anonymous lamda actions.
gj patrick
Sorry, but I do not think you are comparing the same thing. The reason the list.foreach(async...) code did not return anything is because the program terminated right away. If you add a console.ReadLine() at the end, this will allow the tasks created in the loop to do their thing and should display the results.
list.foreach(async...) Doesn't have to 'return' anything. It should write to the console.