Yesterday’s post, “Beware - Parallel.ForEach And Async Don’t Play Well Together”, discussed the predicament I ran into when incorrectly running async code using Parallel.ForEach, which ran the code synchronously anyway.

The code in question was as follows:

AsyncParalle

Which is precisely the wrong approach - async here does not do what you would expect it to do.

In this post, we will look at how to do it correctly.

The solution to this problem is to use the Parallel.ForEachAsync construct, like so:

using Dapper;
using Microsoft.Data.SqlClient;

string[] collection = ["One", "Two", "Three"];

await Parallel.ForEachAsync(collection, async (element, _) =>
{
  await using var cn = new SqlConnection("......");
  await cn.ExecuteAsync("Query", new { ID = element }
  );
});

The discard parameter, _, is where we would pass a CancellationToken, if we had one.

This code will correctly execute the queries in multiple threads without exhausting connections, given that the threads will wait until the execution is complete before creating new connections.

TLDR

Parallel.ForEachAcync is the correct way to execute multiple queries in parallel.

The code is in my GitHub.

Happy hacking!