スポンサーサイト

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

F#入門中級編第19回(Asynchronous Workflows(5))

今回のお題は「Asynchronous Workflows(5) 」です。
 
今回は非同期処理の例外処理とキャンセルについて取り上げます。
まずは例外処理について。
これについては、try withが準備されていて次のような感じで書けます。
 
async{
    try
        let! ***
        do! ***
        .....
    with
    | :? **Exception -> *********
    | :? **Exception -> *********
}
 
捕捉できない例外が発生したとき、その例外は呼び出しもとへと戻っていきます。 
 
例外の処理用にはAsync.CatchメソッドとAsync.RunWithContinuationsメソッドが準備されています。
まずAsync.Catchメソッドの型を調べてみます。
 
> Async.Catch;;
val it : Async<'a> -> Async<Choice<'a,exn>> = <fun:clo@0>    
 
Choice型というのはアクティブパターンのヘルパー型で
 
type Choice<'a,exn>=
    |Choice1Of2 of 'a
    |Choice2Of2 of exn と解釈されます。
 
ということでAsync.Catchは例えば次のように使います。
 
someAsyncTask  //ダミーTask
|> Async.Catch
|> Async.RunSynchronously
|>function
    | Choice1Of2 res -> "結果は%A" res
    | Choice2Of2 (ex : exn) -> "例外が発生しました:%s" ex.Message
 
Async.RunWithContinuationsメソッドについては最後に説明します。
 
次にキャンセル処理について取り上げたいと思います。
Asynchronous workflowのキャンセルは、Thread.abortを使ってスレッドを破棄するというような方法ではなく、let!,do!などが呼び出されたとき、継続処理形式のrest部分の実行を取りやめて、キャンセルhandlerが実行されるという方法で行われます。
 
Async<'T>型の非同期処理実行オブジェクトから、キャンセルされたときどうするかというキャンセルhandlerを付け加えた、新しいAsync<'T>型の非同期処理実行オブジェクトを作り出すメソッドがAsync.TryCancelled<'T> メソッドです。
OperationCanceledException -> unit 型のキャンセルhandlerと、キャンセルhandlerが付け加えられる元のAsync<'T>型の非同期処理実行オブジェクトを引数にします。
 
static member Async.TryCancelled : Async<'T> * (OperationCanceledException -> unit) -> Async<'T>
 
それでは、キャンセルされたとき、自前のキャンセルhandlerが発動される、Async<T'>型のオブジェクトを作ってみます。
 
let whatToDo (s:string,n:int) = 
    async{
            for i in 0 .. (n - 1) do
                printfn "%d %s" i s
                do! Async.Sleep(1000)
            printfn "終了" }
 
let myCancelHandler (ex :OperationCanceledException) =
    printfn "キャンセルされました"
 
let whatToDoWithMyCancelHandler =
    Async.TryCancelled((whatToDo ("not Canceled",10)),myCancelHandler)
 
キャンセルを発動するにはAsync.CancelDefaultToken メソッドを用います。static member Async.Cancel型:DefaultToken : unit -> unit
 
実行例(非同期処理実行中にAsync.CancelDefaultToken();;と入力)
 
0 not Canceled
1 not Canceled
2 not Canceled
3 not Canceled
Async.CancelDefaultToken();;
val it : unit = ()
> キャンセルされました
 
Async.CancelDefaultToken()を使用した場合、キャンセルされるのは、キャンセル後最初に開始されようとする非同期処理になります。CancelTokenというのは、大雑把にいうと、キャンセル伝言板(キャンセルの「のろし、合図」)のようなのもで、非同期処理は、キャンセルするべきか否かそれを見て判断します。(この場合のTokenというのは「しるし、のろし、合図」というような意味合いです。)
 
キャンセルする非同期処理を選択するには、別にキャンセル伝言板を作成して、start時に「これを見ながら実行すること」というように指定します。
例えば次のようにします。
 
let whatToDo (s:string,n:int) = 
    async{
            for i in 0 .. (n - 1) do
                printfn "%s" s
                do! Async.Sleep(1000)
            printfn "おわり" }
 
let cancelHandler1 ex = printfn "task1 was canceled"
let cancelHandler2 ex = printfn "task2 was canceled"
let task1 = Async.TryCancelled((whatToDo ("a",50)),cancelHandler1)
let task2 = Async.TryCancelled((whatToDo ("b",50)),cancelHandler2)
let cancellationSource1 = new CancellationTokenSource()
let cancellationSource2 = new CancellationTokenSource()
Async.Start(task1,cancellationSource1.Token)
Async.Start(task2,cancellationSource2.Token)
 
実行例
> a
b
b
a
b
a
b
a
b
a
cancellationSource2.Cancel();; //入力する
val it : unit = ()
> a
task2 was canceled
a
a
cancellationSource1.Cancel();; //入力する
val it : unit = ()
> task1 was canceled
 
なお、値を返した場合、例外が発生した場合、キャンセルした場合を、一気に設定して実行する方法があります。
これはStartWithContinuationメソッドを用いる方法で、引数として、させる非同期処理、値を返したときの処理、例外が発生したときの処理、キャンセルされたときの処理を並べます。
型は次のようになります。
 
static member Async.StartWithContinuations :
  Async<'T> *
  ('T -> unit) *
  (exn -> unit) *
  (OperationCanceledException -> unit) * 
  CancellationToken option -> unit
 

 
let whatToDo (s:string,n:int) = 
    async{
            for i in 0 .. (n - 1) do
                printfn "%s" s
                do! Async.Sleep(1000)
            return 100*n }
 
let task = whatToDo ("a",50)
Async.StartWithContinuations(
    task,
    (fun result -> printfn "結果は%d" result),
    (fun exn    -> printfn "例外が発生しました。%s " exn.Message),
    (fun oce    -> printfn "キャンセルされました。%s" oce.Message)
)
 
実行例1
> a
a
a
a
中略
a
a
結果は5000
 
実行例2
 
> a
a
a
a
a
Async.CancelDefaultToken();; //入力する
val it : unit = ()
> キャンセルされました。The operation was canceled.
 
 
(参考リンク)
http://msdn.microsoft.com/ja-jp/magazine/cc967279.aspx 
http://www.infoq.com/articles/pickering-fsharp-async 
http://blogs.msdn.com/dsyme/archive/2007/10/11/introducing-f-asynchronous-workflows.aspx   
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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