返回介绍

尝试1:一个幼稚的方案

发布于 2024-08-18 11:54:28 字数 1915 浏览 0 评论 0 收藏 0

让我们来进入下一步,解决这个问题。我们会从一个很直接的方案开始:就是保持一个有时间戳的“事件”列表:

然后我们就可以根据需要计算最近事件的个数。

这段代码易于理解吗?

尽管这个方案是“正确”的,可是其中有很多可读性的问题:

·for循环太大,一口吃不下。大多数读者在读这部分代码时会显著地慢下来(至少他们应该慢下来,如果他们要确定这里的确没有bug的话)。

·MinuteCount()和HourCount()几乎一模一样。如果他们可以共享重复代码就可能让这段代码少一些。这个细节非常重要,因为这些重复的代码相对更复杂。(让有难度的代码约束在一起更好些。)

一个更易读的版本

MinuteCount()和HourCount()中的代码只有一个常量不一样(60和3600)。明显的重构方法是引入一个辅助方法来处理这两种情况:

在这段新代码中有几件事情值得一提。

首先,请注意CountSince()的参数是一个绝对的cutoff,而不是一个相对的secs_ago(60或3600)。两种方式都可行,但是这样做对CountSince()来讲更容易些。

其次,我们把迭代器从i改名为rit。i这个名字更常用在整型索引上。我们考虑过用it这个名字,这是迭代器的一个典型名字。但这一次我们用的是一个反向迭代器,并且这一点对于代码的正确性至关重要。通过在名字前面加一个前缀r,使它在如rit!=events.rend()这样的语句中看上去对称。

最后,把条件rit->time<=cutoff从for循环中抽取出来,并把它作为一条单独的if语句。为什么这么做?因为保持循环的“传统”格式for(begin;end;advance)最容易读。读者会马上明白它是“遍历所有的元素”,并且不需要再做更多的思考。

性能问题

尽管我们改进了代码的外观,但这个设计还有两个严重的性能问题:

1.它一直不停地在变大。

这个类保存着所有它见过的事件——它对内存的使用是没有限制的!最好MinuteHourCounter能自动删除超过一个小时以前的事件,因为不再需要它们了。

2.MinuteCount()和HourCount()太慢了。

CountSince()这个方法的时间为O(n),其中n是在其相关的时间窗口内数据点的个数。想象一下一个高性能服务器每秒调用Add()几百次。每次对HourCount()的调用都可能要对上百万个数据点计数!最好MinuteHourCounter能记住minute_count和hour_count变量,并随每次对Add()的调用而更新。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文