在应用程序中推送数据更改与拉动数据更改

时间:2010-10-29 12:33:10

标签: design-patterns language-agnostic architecture

假设您有一个由两层组成的应用程序:

  • A:存储从数据库或文件
  • 加载的所有数据的数据层
  • B:在良好的用户界面中显示数据的图层,例如图形报告

现在,数据在A层中发生了变化。我们有2种方法可以确保B层的报告得到正确更新。

第一种方法是PUSH方法。 A层通过观察者通知B层,因此B层可以更新其报告。

PUSH方法有几个缺点:

  • 如果数据多次更改(例如在加载期间或在更改大量数据的算法中),观察者将被执行多次。这可以通过引入一种缓冲来解决(在你还在改变的时候阻止调用观察者),但这可能非常棘手,并且通常会忘记正确的缓冲调用。
  • 如果更改了大量数据,观察者调用可能会导致应用程序无法接受的开销。

另一种方法是PULL方法。 A层只记得哪些数据已更改,并且没有发出通知(A层标记为脏)。在用户执行的操作(可能正在运行算法或加载文件或其他内容)之后,我们检查所有用户界面组件,并要求他们自行更新。 在这种情况下,要求层B自我更新。首先,它将检查它的任何底层(A层)是否脏。如果是,它将获得更改并自行更新。如果A层不脏,报告就知道它没什么可做的。

最佳解决方案取决于具体情况。在我的情况下,PUSH方法看起来好多了。

如果我们有超过2层,情况会变得更加困难。假设我们有以下4层:

  • A:存储从数据库或文件
  • 加载的所有数据的数据层
  • B:使用数据层(层A)的层,例如,层。使用复杂的过滤函数来过滤A中的数据
  • C:使用层B的层,例如,将来自B层的数据汇总成较小的信息
  • D:解释C层结果并以清晰的图形方式呈现给用户的报告

在这种情况下,推动这些变化几乎肯定会带来更高的开销。

另一方面,拉出更改需要:

  • 图层D必须调用图层C以询问它是否脏(
  • C层必须调用B层询问它是否脏(
  • B层必须调用A层来询问它是否脏(

如果在你知道实际上什么都没有改变而且你不需要做任何事情之前没有改变任何改变执行的调用量就相当大了。看起来我们试图通过不使用PUSH来避免的性能开销现在又回到了PULL方法中使用,因为有许多调用询问是否有任何问题。

是否存在以良好且高性能(低开销)方式解决此类问题的模式?

2 个答案:

答案 0 :(得分:3)

没有。没有免费的午餐,没有银弹。这一切都归功于精心设计。你已经涵盖了巧妙应用它们的常用技术,需要谨慎和避免假设。

我查询了你的两个陈述:

你暗示控制PUSH通知非常困难。我原本预计在很多情况下你会有一个主计算引擎,它可以抓取数据并进行计算。引擎肯定会在某个时刻停止,此时它可以发送“新数据就绪”事件,该事件可以包含有关更改内容的更细粒度的信息。

你说4次层间通话太贵了。那是什么基础?与什么相比?如果您担心多重因素(10 D实例)调用(5个C实例)调用(2个B实例)调用(1个实例),那么A会被100个调用命中,那么我们肯定会优化吗?每个级别都可以说“如果我正在呼叫或者我最近听到了答案,则无需再次拨打电话”。

当我们考虑图层的缩放优势时,一些便宜的查询可能不会过多。

答案 1 :(得分:0)

通过数据管理器推送,并压缩在不到n纳秒内发生的更改。 数据管理器实现了发布 - 订阅。

这些平均数据生成者只依赖于数据管理器,数据使用者只能获取数据。

(消费者有依赖性逆转。)

这使得胶水代码中的所有数据流管道都清晰可见。 订阅可以提前设置,因此conusmers不需要知道它是如何工作的。

数据管理员可以使用自己的线程来调用订阅者通知,从而将生产者与消费者完美地分离。 您可以轻松压缩更改,因为数据管理器仅使用1个线程进行通知,可以通过计时器“通知”,当它被唤醒时,它只能看到最新的状态。