0

I am trying to understand a comment made on a legacy piece of code...

The original code:

    public async Task Send(Notification notification)
    {
        await Task.WhenAll(notification.Methods.Select(async topic =>
        {
            var client = GetTopicInstance(topic);
            var json = JsonConvert.SerializeObject(notification);
            var message = new Message(Encoding.UTF8.GetBytes(json));
            await client.SendAsync(message); // COMMENT HERE
        }));
    }

The comment made was this:

Return here instead of using await and change the lambda expression to not have the async modifier. This will truly ensure you are running the SendAsync calls in parallel. Right now, due to the await, it will block at every iteration and every SendAsync will be completed sequentially.

So the revised code looks like this:

    public async Task Send(Notification notification)
    {
        await Task.WhenAll(notification.Methods.Select(topic =>
        {
            var client = GetTopicInstance(topic);
            var json = JsonConvert.SerializeObject(notification);
            var message = new Message(Encoding.UTF8.GetBytes(json));
            return client.SendAsync(message);
        }));
    }

What I don't understand is why the second await would cause blocking.

My understanding is that the WhenAll creates a Task for each iteration returned by the Select. The original code would appear (to me) to then create another Task within each of those Tasks. I am unclear why those child Tasks would cause blocking.

Matt W
  • 11,753
  • 25
  • 118
  • 215
  • 2
    The comment is wrong; they are both equivalent as long as an exception is not thrown. – Johnathan Barclay Dec 15 '21 at 13:47
  • @JohnathanBarclay Many exceptions won't even result in different behavior, although you're right that some would. Exceptions in the synchronous code would result in different behavior, and multiple exceptions in the `Task` from `SendAsync` would result in different behavior. – Servy Dec 15 '21 at 13:50
  • 2
    "Right now, due to the await, it will block at every iteration and every SendAsync will be completed sequentially" -> https://dotnetfiddle.net/m2ekKS -> the parallelism is the same regardless of the `await` call because of how the query is evaluated – Camilo Terevinto Dec 15 '21 at 13:58
  • 1
    Take a look at this blog post by Stephen Cleary, if you haven't already read it: [Eliding Async and Await](https://blog.stephencleary.com/2016/12/eliding-async-await.html) – Theodor Zoulias Dec 15 '21 at 14:20

0 Answers0