Alex Alex - 5 months ago 35
C# Question

Asynchronously invoking a parallel for loop

I would like to do something like this:

public async Task MyMethod()
{
// Do some preparation

await Parallel.ForEachAsync(0, count, i => { // Do some work //});

// do some finalization
}


However, I did not find an elegant way of doing so. I thought of two ways, but they are sub-optimal:


  1. The only thing I thought about is manually partitioning the range, creating tasks, and then using Task.WhenAll.

  2. Using the following code
    Task.Factory.StartNew(() => Parallel.For(...));
    .

    The problem is that it "wastes" a thread on the asynchronous task.

  3. Using TPL Dataflow's ActionBlock, and posting the integers one by one. The drawback is that it does not partition the range in a smart way like Parallel.For does, and works on each iteration one by one.

  4. Manually using a Partitioner with Partitioner.Create, but it is less elegant. I want the framework to do intelligent partitioning for me.


Answer

You have a regular synchronous parallel loop that you'd like to invoke asynchronously (presumably to move it off the UI thread).

You can do this the same way you'd move any other CPU-bound work off the UI thread: using Task.Run:

public async Task MyMethod()
{
  // Do some preparation

  await Task.Run(() => Parallel.ForEach(0, count, i => { /* Do some work */ }));

  // do some finalization
}

There is no thread "wasted" because Parallel.ForEach will use the calling thread as one of its worker threads.

(This is recipe 7.4 "Async Wrappers for Parallel Code" in my book).