Theresa
Theresa

Reputation: 21

Run async methods in paralell from non async method

How do I call async methods in paralell from a non async method? I also need to catch exceptions an log them in the calling method.

The implementation below works, but I have read that WaitAny is not recommended, but I have not been able to make it work with for example WhenAll.

Ps, the "real" async methods in my app may take quite a long time to finish, around 10 mins.

class AsyncTest
{

   public void RunAsyncInParalell()
   {
       var tasks = new List<Task>();

       var count = 500;

       for(var i=0; i<count;i++ )
       {
          tasks.Add(AsyncMethod(i));    
        }

        while (tasks.Count() > 0)
        {
            var index = Task.WaitAny(tasks.ToArray());
            try
            {
                var res = tasks[index].Exception;
                if (res != null)
                {
                    res.Flatten();

                    foreach (Exception ex in res.InnerExceptions)
                    {
                        Debug.WriteLine("ERROR: "+ ex.Message, ex);
                    }
                }
            }
            catch (AggregateException aex)
            {

                aex = aex.Flatten();

                foreach (Exception ex in aex.InnerExceptions)
                {
                    Debug.WriteLine("ERROR: " + ex.Message, ex);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("ERROR: " + ex.Message, ex);
            }
            tasks.RemoveAt(index);
        }
    }


    public async Task<int> AsyncMethod(int i)
    {
        var rnd = new Random(DateTime.Now.Millisecond);
        int ticks = rnd.Next(0, 5000);
        if (i == 50)
        {
            throw new Exception("Exception thrown for i=" + i);
        }
        await Task.Delay(ticks);
        return (i);
    }
}

Upvotes: 0

Views: 1044

Answers (2)

Stephen Cleary
Stephen Cleary

Reputation: 456322

How do I call async methods in parallel from a non async method?

The best answer is "you don't". You can, however, call asynchronous methods concurrently from another asynchronous method:

public async Task RunAsync()
{
  var tasks = new List<Task>();
  var count = 500;
  for (var i = 0; i < count; ++i)
    tasks.Add(CallMethodAsync(i));

  await Task.WhenAll(tasks);
}

private async Task CallMethodAsync(int i)
{
  try
  {
    await AsyncMethod(i);
  }
  catch (Exception ex)
  {
    Debug.WriteLine("ERROR: "+ ex.Message, ex);
    throw; // TODO: Decide if this is the behavior you want.
  }
}

The correct way to call RunAsync is with await. If you can't make the calling code async, then first check out my blog series on how to make asynchronous code play well with OOP. If you still can't make the calling code async, then check out the various dubious hacks for mixing asynchronous and synchronous code in my MSDN brownfield async article.

Upvotes: 2

Guillaume
Guillaume

Reputation: 13128

If you want to synchronously wait for all tasks to complete, beware of the context : use ConfigureAwait(false) on each awaited task or wait on a thread that doesn't hold the context.

You can use Task.WaitAll method.

Task.WaitAll(tasks.ToArray());
// Then iterate over tasks to get results

Upvotes: 1

Related Questions