【问题标题】:Why is my MailboxProcessor hanging?为什么我的 MailboxProcessor 挂起?
【发布时间】:2012-05-29 08:33:23
【问题描述】:

我无法弄清楚为什么以下代码在调用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

直接使用相同的 MailboxProcessor 时似乎工作正常,而不是包装在 Aggregator 类中。

【问题讨论】:

    标签: f# mailboxprocessor


    【解决方案1】:

    问题是您没有启动代理。您可以在创建代理后致电Start

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

    或者,您可以使用MailboxProcessor&lt;'T&gt;.Start 创建代理,而不是调用构造函数(我通常更喜欢这个选项,因为它看起来更实用):

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

    我想您无法调试代理,因为代理内部的代码实际上并未运行。我尝试在代理内部调用Receive 之后立即添加printfn "Msg: %A" message(打印传入消息以进行调试),我注意到,在调用Aggregate 之后,代理实际上没有收到任何消息......(它只是在调用GetTotal 后被阻止,它会回复)

    作为旁注,我可能会将GetTotal 转换为方法,因此您可以调用GetTotal()。每次访问属性时都会重新评估属性,因此您的代码执行相同的操作,但最佳实践不建议使用执行复杂工作的属性。

    【讨论】:

      【解决方案2】:

      你忘记启动邮箱了:

      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
      

      【讨论】:

      • 这种情况发生在我身上好几次了,这就是为什么我能够很容易地发现它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-12
      • 1970-01-01
      • 1970-01-01
      • 2015-07-09
      • 1970-01-01
      相关资源
      最近更新 更多