今回は並列処理中に発生した例外の扱い方について見ていきます。
TPLの例外
通常例外処理をする場合、特に何も意識することなく発生するであろう例外の型をcatchに書くでしょう。しかし処理が並列に実行されているとなると、同時に複数の例外が発生する可能性があることを考慮しなければなりません。
ある並列処理中に例外が発生した場合、TPLは実行中の他の並列処理の停止を試みます。しかし、停止を試みるまでの間に (= 同時に複数の) 例外が発生する可能性があります。TPLではこれを考慮した設計がなされており、新たにSystem.AggregateExceptionクラスが実装されました。TPLによる並列処理が行われるコードをAggregateExceptionを補足するように try - catch 構文で括ることで、並列処理中に発生した例外を処理することができるようになっています。
サンプル
以下にそのサンプルを示します。
using System; using System.Linq; using System.Threading.Tasks; namespace Sample08_LoopException { class Program { static void Main() { try { Parallel.ForEach(Enumerable.Range(0, 100), value => { if (value % 2== 0) throw new InvalidOperationException(); else throw new ArgumentException(); }); } catch (AggregateException ex) { foreach (var exception in ex.InnerExceptions) Console.WriteLine(exception.GetType().Name); } } } } //----- 結果 (例) /* InvalidOperationException InvalidOperationException ArgumentException ArgumentException InvalidOperationException InvalidOperationException ArgumentException ArgumentException InvalidOperationException */
上のサンプルでは挙動を知りたいだけなので、複数の例外が発生するように意図的にthrowを記述しています。Parallel.ForEachの内部で発生した例外はAggregateExceptionのInnerExceptionsプロパティにすべて格納されます。あとは、catch文の中で各例外に応じた適当な後処理を行えば良いということになります。
次回予告
今回は並列処理中に発生した例外の扱い方について見てきました。この方法はParallel.For/ForEachだけでなくTPL全般で同じように扱うことができますので、ぜひ覚えておいてください。次回は並列ループの取り消しについて見て行こうと思います。