I want to know if you think this is a good way to handle exceptions thrown by Parallel Loops (Parallel.ForEach and/or Parallel.For) inside Tasks.
I think it isn't so bad, but your opinion can be usefull to me! Hope you can throw some light on me!
(I used VS2010 and, of course, Framework 4.0)
class Program
{
private static ConcurrentQueue<Exception> _exceptions = new ConcurrentQueue<Exception>();
private static readonly ExceptionManager _exceptionManager = new ExceptionManager();
static void Main()
{
var process = new SomeProcess(_exceptions);
var otherProcess = new SomeOtherProcess(_exceptions);
var someProcess = new Task(() =>
{
process.InitSomeProcess();
process.DoSomeProcess();
});
var someOtherProcess = new Task(() =>
{
otherProcess.InitSomeOtherProcess();
otherProcess.DoSomeOtherProcess();
});
someProcess.Start();
someOtherProcess.Start();
try
{
someProcess.Wait();
someOtherProcess.Wait();
}
catch ( Exception ex)
{
_exceptionManager.Manage(ex);
}
finally
{
Console.WriteLine();
foreach ( var exception in _exceptions )
{
_exceptionManager.Manage(exception);
}
_exceptions = new ConcurrentQueue<Exception>(); //Delete exceptiones to prevent manage them twice (maybe this could be one in a more elegant way).
}
Console.ReadKey();
}
}
public class ExceptionManager
{
public void Manage(Exception ex)
{
Console.WriteLine("Se dió una {0}: {1}", ex.GetType(), ex.Message);
}
}
public class SomeProcess
{
private readonly ConcurrentQueue<Exception> _exceptions;
public SomeProcess(ConcurrentQueue<Exception> exceptions)
{
_exceptions = exceptions;
}
public void InitSomeProcess()
{
Parallel.For(0, 20, (i, b) =>
{
try
{
Console.WriteLine("Initializing SomeProcess on {0}.", i);
throw new InvalidOperationException("SomeProcess was unable to Initialize " + i);
}
catch (Exception ex)
{
_exceptions.Enqueue(ex);
}
});
Console.WriteLine("SomeProcess initialized :D");
}
public void DoSomeProcess()
{
Parallel.For(0, 20, (i, b) =>
{
try
{
Console.WriteLine("Doing SomeProcess on {0}.", i);
throw new InvalidOperationException("SomeProcess was unable to process " + i);
}
catch (Exception ex)
{
_exceptions.Enqueue(ex);
}
});
Console.WriteLine("SomeProcess done :D");
}
}
public class SomeOtherProcess
{
private readonly ConcurrentQueue<Exception> _exceptions;
public SomeOtherProcess(ConcurrentQueue<Exception> exceptions)
{
_exceptions = exceptions;
}
public void InitSomeOtherProcess()
{
Parallel.For(0, 20, (i, b) =>
{
try
{
Console.WriteLine("Initializing SomeOtherProcess on {0}.", i);
throw new InvalidOperationException("SomeOtherProcess was unable to Initialize " + i);
}
catch (Exception ex)
{
_exceptions.Enqueue(ex);
}
});
Console.WriteLine("SomeOtherProcess initialized :D");
}
public void DoSomeOtherProcess()
{
Parallel.For(0, 20, (i, b) =>
{
try
{
Console.WriteLine("Doing SomeOtherProcess on开发者_StackOverflow {0}.", i);
throw new InvalidOperationException("SomeOtherProcess was unable to process " + i);
}
catch (Exception ex)
{
_exceptions.Enqueue(ex);
}
});
Console.WriteLine("SomeOtherProcess done! :D");
}
}
if you think this is a good way to handle exceptions thrown by Parallel Loops ... inside Tasks.
Hard to tell for 'SomeProcess'. This depends on a combination of your business rules and technical issues.
The TPL has an excellent mechanism to collect exceptions inside Tasks and pro[agate them to the caller, so think about what you really need.
Edit, after the formatting was fixed:
If you are really sure that your loop should continue with the next item after an exception then your enqueue approach looks acceptable. Again, it depends on what the loop is doing.
精彩评论