4

Why does the following crash if run inside a console application instead of throwing an AggregateException and being caught by the outer try/catch?

I've simplified the use case for the await for brevity, but in the relevant code I am indeed trying to execute an awaitable Task of importance.

var list = new List<string>() {"Error"};

        try
        {
            Parallel.ForEach(list, new ParallelOptions()
            {
                MaxDegreeOfParallelism = 8
            }, async listEntry =>
            {
                await Task.Delay(5000);
                throw new Exception("Exception");
            });
        }
        catch (Exception ex)
        {
            //never hits, the application crashes
        }

        Console.ReadLine();

I note that the following does not cause the application to fail, and an exception is indeed caught, but I do not understand what's really going on as to what is fundamentally different about the two contexts:

var list = new List<string>() {"Error"};

        try
        {
            Parallel.ForEach(list, new ParallelOptions()
            {
                MaxDegreeOfParallelism = 8
            }, listEntry =>
            {

                throw new Exception("Exception");
            });
        }
        catch (Exception ex)
        {
            //exception is caught, application continues
        }

        Console.ReadLine();
14
  • I don't see any code that catches exception on async part of your tasks - which indeed leads to unhanded exceptions and termination of process... Side note: I'm not really sure why you need Parallel.ForEach to start multiple tasks when you don't care how they end... You may search for "C# fire-and-forget async" if you actually need code similar to one in this post. Commented Jul 8, 2016 at 0:49
  • @AlexeiLevenkov, I guess my question is...why do I need to catch it inside of the loop simply because it's asychronous? When it's synchronous, it does not require that. Also, this isn't for a fire and forget, in my actual code I'm making a call to a function that is awaitable, I just simplified the use case for brevity with an empty task. Commented Jul 8, 2016 at 0:52
  • 3
    Don't mix Parallel.ForEach with async/await stackoverflow.com/questions/11564506/… Commented Jul 8, 2016 at 0:58
  • @GrantH. if you are not await-ing them it is fire-and-forget (broken in the way you see it). If your actual code has await - makes sure to update the code. (Note: I think Task.Delay(1) is better and more compact way to demonstrate awaitable code than Task.Run.) Commented Jul 8, 2016 at 1:06
  • 1
    @MickyD, thanks for the link, that's very helpful, seems like my whole approach is a bit off. Commented Jul 8, 2016 at 1:24

1 Answer 1

10

As already mentioned in comments, you shouldn't mix async and Parallel.ForEach, they don't work together.

What you're observing is one of the consequences of that: the lambda is compiled as an async void method and when an async void method throws, the exception is rethrown on its SynchronizationContext, which will normally crash the application.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.