简体   繁体   English

邮箱处理器,最新消息

[英]Mailboxprocessor, latest message

The setup is similar to this . 设置类似于 One agent, ( dataSource ) is generating data, and a single agent ( dataProcessor ) is processing the data. 一个代理( dataSource )正在生成数据,而单个代理( dataProcessor )正在处理数据。 There is a lot more data being generated than dataProcessor can process, and I am not interested in processing all messages, just processing the latest piece of data. 生成的数据比dataProcessor可以处理的要dataProcessor ,我对处理所有消息不感兴趣,只是处理最新的数据。

One possible solution, proposed there by Jon Harrop there "is to greedily eat all messages in the inbox when one arrives and discard all but the most recent". Jon Harrop在那里提出的一个可能的解决方案是“当一个人到达时贪婪地吃收件箱中的所有信息并丢弃除了最近的所有信息”。 Another approach is not to listen for all messages, but rather for dataProcessor to PostAndReply dataSource to get the latest piece of data. 另一种方法是不监听所有消息,而是dataProcessorPostAndReply dataSource以获取最新的数据。

What are the pros and cons of these approaches? 这些方法的优点和缺点是什么?

This is an intriguing question and there are quite likely several possible perspectives. 这是一个有趣的问题,很可能有几个可能的观点。 I think the most notable aspect is that the choice will affect how you design the API at the interface between the two components: 我认为最值得注意的方面是选择将影响您在两个组件之间的接口上设计API的方式:

  1. In "Consume all" approach, the producer has a very simple API where it triggers some event whenever a value is produced and your consumer will subscribe to it. 在“Consume all”方法中,生产者有一个非常简单的API,每当产生一个值并且你的消费者会订阅它时它会触发一些事件。 This means that you could have other subscribers listening to updates from the producer and doing something else than your consumer from this question. 这意味着您可以让其他订阅者从生产者那里收听更新,并从此问题中做出除消费者之外的其他操作。

  2. In "Call to get latest" approach, the producer will presumably need to be written so that it keeps the current state and discards old values. 在“Call to get latest”方法中,可能需要编写生成器以使其保持当前状态并丢弃旧值。 It will then provide blocking async API to get the latest value. 然后它将提供阻止异步API以获取最新值。 It could still expose an event for other consumers though. 它仍然可以为其他消费者揭露一个事件。 The consumer will need to actively poll for changes (in a busy loop of some sorts). 消费者需要主动轮询更改(在某些类型的繁忙循环中)。

  3. You could also have a producer with an event as in "Consume all", but then create another component that listens to any given event, keeps the latest value and makes it available via a blocking async call to any other client. 您也可以在“Consume all”中拥有一个带有事件的生产者,但随后创建另一个侦听任何给定事件的组件,保留最新值并通过阻止异步调用使其可用于任何其他客户端。

Here some advantages/disadvantages I can think of: 这里有一些我能想到的优点/缺点:

  • In (1) the producer is very simple; 在(1)中,制作人非常简单; the consumer is harder to write 消费者更难写
  • In (2) the producer needs to do a bit more work, but the consumer is simple 在(2)中,生产者需要做更多的工作,但消费者很简单
  • In (3), you are adding another layer, but in a fairly reusable way. 在(3)中,您正在添加另一个层,但是以相当可重用的方式。

I would probably go with either (2) (if I only need this for one data source) or with (3) after checking that it does not affect the performance. 我可能会选择(2)(如果我只需要一个数据源)或者(3)检查它不会影响性能。

As for (3), the sketch of what I was thinking would look something like this: 至于(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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM