スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#中級編 並列プログラミング(3) 例外

今回は並行プログラミング時の例外の紹介です。
 
まずは関数を定義しておきます。
> let throwExcFunc (id : int) () =
     failwith (sprintf "ID:%dで例外を発生させました" id)
     () ;;
 
val throwExcFunc : int -> unit -> unit
 
次に関数
> let tef1 = throwExcFunc 1;;
val tef1 : (unit -> unit)
 
として通常の形でtyr withを使って実行してみます。
 
> try 
    tef1 ()
with
| ex -> printfn "type = %A  mes = %A " (ex.GetType ()) ex.Message   ;;
 
type = System.Exception  mes = "ID:1で例外を発生させました" 
val it : unit = ()
 
それでは並行処理で実行してみます。
 
> try
    let task = Task.Factory.StartNew(fun () -> tef1 ())
    printfn "%d" task.Result
with
| ex -> printfn "type = %A  mes = %A " (ex.GetType ()) ex.Message ;;
type = System.AggregateException  mes = "1 つ以上のエラーが発生しました。" 
val it : unit = ()
 
ということでSystem.AggregateExceptionなるものが発生しました。
aggregateとは何というと「集合した」とかいう意味です。(ちなみにList.fold系の関数はaggregate系の関数とも言われます。)
なぜこのような例外が返ってくるようにしてあるかというと、スレッドからさらに複数のスレッドを呼び出し、それら中のスレッドから例外が発生した場合(場合によっては複数)のために、入れ子状になった(一つ以上の)例外を返せるメカニズムが必要となるわけです。
では、さきほどの例に戻りますが、実際の例外はAggregateExceptonのInnerExceptionsプロパティに保存されています。
ではちょっとコードを変えてみます。
 
> try
    let task = Task.Factory.StartNew(fun () -> tef1 ())
    printfn "%d" task.Result
with
| :? AggregateException as ae ->  
        for innerEx in ae.InnerExceptions do
            printfn "type = %A  mes = %A " (innerEx.GetType ()) innerEx.Message;;
 
type = System.Exception  mes = "ID:1で例外を発生させました" 
 
val it : unit = ()
 
では次に並列処理を入れ子にして,もっと深いところで例外を発生させてみます。
 

try
    let task = Task.Factory.StartNew(fun () -> let task1 = Task.Factory.StartNew(fun () -> tef1 ())
                                               printfn "%d" task1.Result //ここは実行されない
                                               task1.Result)//ここは実行されない 
            
    printfn "%d" task.Result
with    
| :? AggregateException as ae ->  
        for innerEx in ae.InnerExceptions do
            printfn "type = %A  mes = %A " (innerEx.GetType ()) innerEx.Message
 
;;
 
type = System.AggregateException  mes = "1 つ以上のエラーが発生しました。" 
 
val throwExcFunc : int -> unit -> int
val tef1 : (unit -> int)
 

ということで、呼び出し側のAggregateExceptionのInnerExceptionsより、さらに深いところで例外がthrowされているので、このような結果になります。さらに深いところまで下りて行って、結果を取ってくるには、Flattenメソッドか再帰処理を使います。
 
(1)Flattenメソッドを使った例
 

try
    let task = Task.Factory.StartNew(fun () -> let task1 = Task.Factory.StartNew(fun () -> tef1 ())
                                               task1.Result)//ここまでこない) 
            
    printfn "%d" task.Result //ここまでこない
with    
| :? AggregateException as ae ->  
        let t = ae.Flatten() //入れ子になった例外を一つのAggreateExceptionにまとめる
        for innerEx in t.InnerExceptions do
            printfn "type = %A  mes = %A " (innerEx.GetType ()) innerEx.Message;;
 
 
type = System.Exception  mes = "ID:1で例外を発生させました" 
val it : unit = ()
 
(2)再帰処理を行った例
 
> try
    let task = Task.Factory.StartNew(fun () -> let task1 = Task.Factory.StartNew(fun () -> tef1 ())
                                               task1.Result)//ここまでこない) 
            
    printfn "%d" task.Result //ここまでこない
with    
| :? AggregateException as ae ->
    let rec decAggregEx (ae : AggregateException) = //再帰関数の定義
        [
              for innerEx in ae.InnerExceptions do
              match innerEx with
                | :? AggregateException as ae -> yield! decAggregEx ae
                | _ -> yield innerEx
        ]
    decAggregEx ae
    |> List.iter (fun ex -> printfn "type = %A  mes = %A " (ex.GetType ()) ex.Message);;
 
 
type = System.Exception  mes = "ID:1で例外を発生させました" 
val it : unit = ()
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。