这是一个有趣的问题,很可能有几种可能的观点。我认为最值得注意的方面是选择会影响您在两个组件之间的接口处设计 API 的方式:
在“全部消费”方法中,生产者有一个非常简单的 API,只要产生一个值,它就会触发一些事件,并且您的消费者将订阅它。这意味着您可以让其他订阅者从生产者那里收听更新,并从这个问题中做一些不同于您的消费者的事情。
在“调用获取最新”方法中,可能需要编写生产者以保持当前状态并丢弃旧值。然后它将提供阻塞异步 API 以获取最新值。不过,它仍然可以为其他消费者公开一个事件。消费者将需要主动轮询更改(在某种繁忙的循环中)。
你也可以有一个像“Consume all”中的事件的生产者,然后创建另一个组件来监听任何给定的事件,保持最新的值,并通过阻塞异步调用任何其他客户端使其可用。
这里有一些我能想到的优点/缺点:
- (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)