0

There is an API Async method (GetMatrix) which takes a row number of a square matrix as input parameter and responds back with the values in that row.

I need to construct the whole matrix by calling the API multiple times (row size of the matrix times).

Right now I have initialized a jagged array and I'm sending async calls to that API in a "For loop" like below.

var matrix = new int[size][];

for (int i = 0; i < size; i++)
{
     matrix[i] = await GetMatrix(i);
}

It's taking a decent amount of time to construct the whole matrix if the matrix is of huge size (like 1000 rows).

Can we create parallel tasks in conjunction with the above async calls? I think it will be faster than just async calls. How can we do that in C#?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Mr.V
  • 17
  • 2
  • 3
    `tasks.Add(GetMatrix(i));` (where `tasks` is a `List>` I think. Then `Task.WhenAll` and iterate over the tasks. – mjwills Dec 27 '20 at 12:47
  • Could you try configuring the `await` with `.ConfigureAwait(false)`, and see if it makes any difference? – Theodor Zoulias Dec 27 '20 at 19:59
  • I tried @mjwills suggestion, it worked liked a charm. – Mr.V Dec 28 '20 at 00:22
  • @TheodorZoulias what will ConfigureAwait(false) do?? Does it usually reduce time than the normal await ?? – Mr.V Dec 28 '20 at 00:28
  • 1
    The `ConfigureAwait(false)` prevents the continuation after each `await` ro run on the captured `SynchronizationContext`, which could be the UI thread, depending on the type of your app. If your app has GUI, setting the `ConfigureAwait(false)` could have some positive effect to the performance of the whole operation. – Theodor Zoulias Dec 28 '20 at 06:49

2 Answers2

2

Can we create parallel tasks in conjunction with the above async calls?

What you're looking for is asynchronous concurrency, which is most commonly done with Task.WhenAll:

var sizes = Enumerable.Range(0, size);
var tasks = sizes.Select(GetMatrix).ToList();
var matrix = await Task.WhenAll(tasks);

Side note: ContinueWith is dangerous.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
1

If your method doesn't require to be async then you can try to use Parallel.For like this var matrix = new int[size][]; Parallel.For(0, size, async i => { matrix[i] = await GetMatrix(i); });

But if your method should be async then you could do something like mjwills said:

    var matrix = new int[size][];
    var tasks = new Task[size];

    for (int i = 0; i < size; i++)
    {
        var local = i;
        tasks[i] = GetMatrix(i).ContinueWith(t => matrix[local] = t.Result);
    }

    await Task.WhenAll(tasks);
Arjen
  • 290
  • 3
  • 6
  • 2
    The `Parallel.ForEach` [is not async-friendly](https://stackoverflow.com/questions/15136542/parallel-foreach-with-asynchronous-lambda). The lambda passed is [async void](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#avoid-async-void). – Theodor Zoulias Dec 27 '20 at 19:57
  • 1
    @TheodorZoulias you're completly right. Nevermind my first answer. – Arjen Dec 27 '20 at 20:56