0

I would like each record in ForEach run Async. I don't have to wait for each result, so I can just iterate through the list and commission the record executed in the next Thread. But in the end, I need to return this list with all executed methods. Does anyone know how I could refactor this example code?

Example:

List<SomeObject> CalculateMissingVar(List<SomeObject> records)
{
    foreach (var record in records)
    {
        //I woudl like run this method async without wating for each result
        record.PlaceForLongMathEquation = Calculate(5);
    }

    return records;
}

//This method shodul be Async
int Calculate(int number)
{
    return number * number;
}

2 Answers2

3

Proper error handling omitted for compactness:

async Task CalculateMissingVar(List<SomeObject> records)
{
    await Task.WhenAll(records.Select(Calculate));
}

async Task Calculate(SomeObject record)
{
    ...
    record.PlaceForLongMathEquation = x;
}
Oliver Weichhold
  • 10,259
  • 5
  • 45
  • 87
  • Does this actually do what was asked? The Calculate() method in the question takes a number as the argument, not the record. Apart from that, Task.WhenAll() is indeed an asynchronous way to solve this. – Julian Oct 17 '22 at 21:48
  • @ewerspej I short-circuited the logic since all he did in his example was to assign the result to an instance field. – Oliver Weichhold Oct 17 '22 at 21:49
  • I see that and it generally makes sense. I was just curious, because this way the argument is not passed to the Calculate() method anymore. – Julian Oct 18 '22 at 17:31
1

If each iteration of your loop does not depend on the previous iteration then you can use Parallel.ForEach, it sounds like this is exactly what you are looking for (it performs all iterations of the loops asynchronously in parallel with each other according to the number of cores on your server)

You can read about it here https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-write-a-simple-parallel-foreach-loop

List<SomeObject> CalculateMissingVar(List<SomeObject> records)
{
    Parallel.ForEach(records, record =>
    {
        //I woudl like run this method async without wating for each result
        record.PlaceForLongMathEquation = Calculate(5);
    }

    return records;
}
Haim Abeles
  • 982
  • 6
  • 19
  • 1
    While the answer fits the question, I would like to point out that Parallel.ForEach() is not running asynchronously. There is a difference between parallelism and the async-await pattern: https://stackoverflow.com/questions/14099520/async-await-and-parallel-in-c-sharp#14099602 – Julian Oct 17 '22 at 21:36
  • 1
    You are absolutely right, excellent comment! – Haim Abeles Oct 17 '22 at 21:39
  • 1
    Mind that Parallel.ForEach() is a blocking operation in itself. – Julian Oct 17 '22 at 21:41
  • Interestingly, I will have a maximum of 50 records to calculate, and operating on a small list of objects, using Parallel.ForEach gives me more time than normal ForEach – Mahatma Gandhi Oct 18 '22 at 16:08
  • @MahatmaGandhi This is because your list is small, you can see an explanation here https://stackoverflow.com/questions/39540106/parallel-foreach-slower-than-normal-foreach – Haim Abeles Oct 18 '22 at 16:24
  • @HaimAbeles here i found also great explanation https://stackoverflow.com/questions/6036120/parallel-foreach-slower-than-foreach When i added extra 50k records i started seeing that Parallel.ForEach is little bit faster. – Mahatma Gandhi Oct 19 '22 at 06:41
  • @MahatmaGandhi If my answer answered your question, I would appreciate it if you marked it as the correct answer – Haim Abeles Oct 19 '22 at 07:39