3

への呼び出しで次のコードがハングする理由がわかりませんGetTotal。MailboxProcessor 内でデバッグできないようで、何が起こっているのかわかりにくいです。

module Aggregator

open System

type Message<'T, 'TState> =
    | Aggregate of 'T
    | GetTotal of AsyncReplyChannel<'TState>

type Aggregator<'T, 'TState>(initialState, f) =
    let myAgent = new MailboxProcessor<Message<'T, 'TState>>(fun inbox ->
        let rec loop agg =
            async {
                let! message = inbox.Receive()
                match message with
                    | Aggregate x -> return! loop (f agg x)
                    | GetTotal replyChannel ->
                        replyChannel.Reply(agg)
                        return! loop agg
            }
        loop initialState
        )

    member m.Aggregate x = myAgent.Post(Aggregate(x))
    member m.GetTotal = myAgent.PostAndReply(fun replyChannel -> GetTotal(replyChannel))

let myAggregator = new Aggregator<int, int>(0, (+))

myAggregator.Aggregate(3)
myAggregator.Aggregate(4)
myAggregator.Aggregate(5)

let totalSoFar = myAggregator.GetTotal
printfn "%d" totalSoFar

Console.ReadLine() |> ignore

Aggregatorクラスにラップするのではなく、同一の MailboxProcessor を直接使用するとうまくいくようです。

4

2 に答える 2

7

問題は、エージェントを開始しなかったことです。Startエージェントを作成した後、次のいずれかに電話をかけることができます。

let myAgent = (...)
do myAgent.Start()

または、コンストラクターを呼び出す代わりに、を使用してエージェントを作成することもできますMailboxProcessor<'T>.Start(より機能的に見えるため、通常はこのオプションを使用します)。

let myAgent = MailboxProcessor<Message<'T, 'TState>>.Start(fun inbox ->  (...) )

エージェント内のコードが実際に実行されていなかったため、エージェントをデバッグできなかったと思います。printfn "Msg: %A" messageエージェント内への呼び出しの直後に追加しようとしましたが(デバッグ用に着信メッセージを出力するため)、呼び出した後、エージェントが実際にメッセージを受信しなかっReceiveたことに気付きました...(呼び出し後にのみブロックされ、応答が利用可能です)AggregateGetTotal

ちなみに、私はおそらくGetTotalメソッドに変わるので、を呼び出しますGetTotal()。プロパティは、アクセスするたびに再評価されるため、コードは同じことを行いますが、複雑な作業を行うプロパティの使用はベストプラクティスでは推奨されていません。

于 2012-05-29T08:49:06.970 に答える
4

メールボックスを開始するのを忘れました:

open System

type Message<'T, 'TState> =
    | Aggregate of 'T
    | GetTotal of AsyncReplyChannel<'TState>

type Aggregator<'T, 'TState>(initialState, f) =
    let myAgent = new MailboxProcessor<Message<'T, 'TState>>(fun inbox ->
        let rec loop agg =
            async {
                let! message = inbox.Receive()
                match message with
                    | Aggregate x -> return! loop (f agg x)
                    | GetTotal replyChannel ->
                        replyChannel.Reply(agg)
                        return! loop agg
            }
        loop initialState
        )

    member m.Aggregate x = myAgent.Post(Aggregate(x))
    member m.GetTotal = myAgent.PostAndReply(fun replyChannel -> GetTotal(replyChannel))
    member m.Start() = myAgent.Start()

let myAggregator = new Aggregator<int, int>(0, (+))

myAggregator.Start()

myAggregator.Aggregate(3)
myAggregator.Aggregate(4)
myAggregator.Aggregate(5)

let totalSoFar = myAggregator.GetTotal
printfn "%d" totalSoFar

Console.ReadLine() |> ignore
于 2012-05-29T08:49:21.200 に答える