邮箱处理器,最新消息

时间:2017-10-14 17:14:24

标签: f# mailboxprocessor

设置类似于this。 一个代理(dataSource)正在生成数据,而单个代理(dataProcessor)正在处理数据。生成的数据比dataProcessor可以处理的要多得多,我对处理所有消息不感兴趣,只是处理最新的数据。

Jon Harrop在那里提出的一个可能的解决方案是,当一个人到达时,贪婪地吃收件箱中的所有邮件,丢弃除最近的所有邮件之外的所有邮件。 另一种方法不是收听所有邮件,而是收听dataProcessorPostAndReply dataSource以获取最新的数据。

这些方法的优点和缺点是什么?

1 个答案:

答案 0 :(得分:3)

这是一个有趣的问题,很可能有几种可能的观点。我认为最值得注意的方面是选择将影响您在两个组件之间的接口上设计API的方式:

  1. In"消费所有"方法,生产者有一个非常简单的API,每当产生一个值并且你的消费者会订阅它时它会触发一些事件。这意味着你可以让其他订阅者从这个问题中听取制作人的更新,并做一些比消费者更多的事情。

  2. In"致电获取最新消息"方法,生产者可能需要编写,以便保持当前状态并丢弃旧值。然后它将提供阻止异步API以获取最新值。它仍然可以为其他消费者揭露一个事件。消费者需要主动轮询更改(在某些类型的繁忙循环中)。

  3. 你也可以让一个生产者参与"消费所有",然后创建另一个组件来监听任何给定的事件,保留最新的值并通过阻止使其可用异步调用任何其他客户端。

  4. 我可以想到一些优点/缺点:

    • 在(1)中,制作人非常简单;消费者更难写
    • 在(2)中,制作人需要做更多的工作,但消费者很简单
    • 在(3)中,您正在添加另一个图层,但是以相当可重用的方式。

    我可能会选择(2)(如果我只需要一个数据源)或者(3)检查它不会影响性能。

    至于(3),我所想的是这样的草图:

    type KeepLastMessage<'T> = 
      | Update of 'T
      | Get of AsyncReplyChannel<'T>
    
    type KeepLast<'T>(initial:'T, event:IObservable<'T>) = 
      let agent = MailboxProcessor.Start(fun inbox -> 
        let rec loop last = async {
          let! msg = inbox.Receive()
          match msg with 
          | Update last -> return! loop last
          | Get ch -> ch.Reply(last); return! loop last }
        loop initial)
      member x.AsyncGet() = agent.PostAndAsyncReply(Get)