スポンサーサイト

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

F#入門中級編第21回(Asynchronous Workflows(7) MailboxProcessor(2))

さて今回は作業途中のagentから何らかの値を返してもらうことにします。
そのために、agentの処理するメッセージの種類の一つとしてFetch of AsynReplyChannel<_>を追加します。
Fetchというのは、「(かすめ)取ってくる」というような意味です。(特にFetchでないといけないわけではありませんが、通例としてこの名前を使うことが多いようです。)
AsynReplyChannel<_>クラスは、agentが何らかの値を返す為に利用するハンドルを定義したクラスで、インスタンスはただ一つのメソッドReplyをもちます。このメソッドの型は
AsyncReplyChannel<'Reply> -> 'Reply -> unit
となっています。
それでは例を一つ
 
>type msg = 
    |Work of int
    |Stop
    |Fetch of AsyncReplyChannel<int list>
 
let fetchableAgent00 = MailboxProcessor.Start(fun inbox ->
                        let rec loop lst =
                            async{let! msg = inbox.Receive()
                                  match msg with
                                  | Work(i) ->
                                    return! loop (i::lst) 
                                  | Stop ->
                                    return ()
                                  | Fetch(replyChannel) -> //返答に使うハンドルであるreplyChannelにマッチ
                                        replyChannel.Reply(lst) //仕事履歴であるlstを返す
                                        return! loop (lst)
                            }
                        loop []  );;
 
 
type msg =
  | Work of int
  | Stop
  | Fetch of AsyncReplyChannel<int list>
val fetchableAgent00 : MailboxProcessor<msg>
 
> fetchableAgent00.Post(Work(1));;
val it : unit = ()
> fetchableAgent00.Post(Work(2));;
val it : unit = ()
 
さて、agentから、値をFetchしてくるにはPostAndReplyメソッドを利用します。
これは
 
member this.PostAndReply : MailboxProcessor<'Msg> -> (AsyncReplyChannel<'Reply> -> 'Msg)  -> 'Reply
 
という形で定義されてますので、上の例ではAsyncReplyChannel<int list> -> 'Msg型の関数すなわち
AsyncReplyChannel<int list> -> Fetch of AsyncReplyChannel<int list> 型の関数を渡す必要があります。
ここではF#の型推論機能にまかせて、次のようにします。
 
> fetchableAgent00.PostAndReply(fun replyChannel -> Fetch(replyChannel));;
 
val it : int list = [2; 1]
 
PostAndReplyによって、暗黙にAsyncReplyChannel<int list>型のインスタンスreplyChannelが生成され、この関数を適用した結果の、Fetch(replyChannel)がメッセージキューに挿入されて、パターンマッチにより処理されると考えればよいかと思います。
 
なおPostAndReplyはsyncronous methodです。
 
それでは処理を続けてみます。
 
> fetchableAgent00.Post(Work(3));;
val it : unit = ()
 
> fetchableAgent00.PostAndReply(fun replyChannel -> Fetch(replyChannel));;
val it : int list = [3; 2; 1]
 
> fetchableAgent00.Post(Stop);;
val it : unit = ()
 
最後にメッセージキューに整数を入れると、それらの和と、偶数だけの和を保持しながら働くというagentを作成してみます。全ての和も偶数だけの和もFetchできるようにすることにします。
 
type msg = 
    |Work of int
    |Stop
    |FetchAllSum of AsyncReplyChannel<int>
    |FetchEvenSum of AsyncReplyChannel<int>
 
let fetchable2wayAgent00 = MailboxProcessor.Start(fun inbox ->
                        let rec loop (allSum,evenSum) =
                            async{let! msg = inbox.Receive()
                                  match msg with
                                  | Work(i) ->
                                        let newAllSum = allSum + i 
                                        let newEvenSum =
                                            if i % 2 = 0 then
                                                evenSum + i
                                            else
                                                evenSum
                                        
                                        return! loop (newAllSum,newEvenSum) 
                                  | Stop ->
                                    return ()
                                  | FetchAllSum(replyChannel) -> 
                                        replyChannel.Reply(allSum) 
                                        return! loop (allSum,evenSum)
                                  | FetchEvenSum(replyChannel) ->
                                        replyChannel.Reply(evenSum)
                                        return! loop (allSum,evenSum)
                            }
                        loop (0,0))
                        
実行例
> fetchable2wayAgent00.Post(Work(1));;
val it : unit = ()
 
> fetchable2wayAgent00.Post(Work(2));;
val it : unit = ()
 
> fetchable2wayAgent00.PostAndReply(fun replyChannel -> FetchAllSum(replyChannel));;
val it : int = 3
 
> fetchable2wayAgent00.PostAndReply(fun replyChannel -> FetchEvenSum(replyChannel));;
val it : int = 2
 
> fetchable2wayAgent00.Post(Stop);;
val it : unit = ()
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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