Reputation: 21
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
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
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