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代理内部(打印传入消息以进行调试),我注意到,在调用之后Aggregate,代理实际上没有收到任何消息......(它只在调用后阻塞GetTotal,它会回复)

作为旁注,我可能会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 回答