一个简单的低通滤波器就可以确保不产生误差。但是,如果您对测量传输率有更深入的思考,您就会开始维护单独的整数计数器以正确地完成它。
如果您希望它是一个精确的计数,请注意有一个可用的简化。首先,在处理速率时,它们的算术平均值不适用于字节/秒(秒/字节更正确 - 这会导致调和平均值)。另一个问题是它们应该被加权。正因为如此,简单地保持 int64 运行总字节数与观察时间的关系实际上是正确的——听起来很愚蠢。通常,您对每个 w 加权 1/n。看看当你按时间衡量时发生的一个简洁的简化:
(w0*b0/t0 + w1*b1/t1 + w2*b2/t2 + ...)/(w0+w1+w2+...)
总字节数/总重量
(b0+b1+b2+...)/(w0+w1+w2+...)
因此,只需将字节和毫秒的总数分开(int64!)。并且仅将它们划分为渲染步骤以可视化速率。请注意,如果您改为使用调和平均值(您应该对速率执行此操作 - 因为您实际上是在平均秒/字节),那么这与发送一个字节所需的时间相同,由有多少字节加权。
1 / (( w0*t0/b0 + w1*t1/b0 + ... )/(w0+w1+w2+...)) = totalBytes/totalTime
因此,按时间加权的算术平均值与按字节加权的调和平均值相同。只需在一个变量中保持运行总字节数,在另一个变量中保持时间。有一个更深层次的原因是,这个简单的计数实际上是正确的。想想积分。假设没有并发,这实际上只是传输的总字节数除以总观察时间。假设计算机实际上每毫秒走 1 步,并且只发送整个字节 - 并且您观察整个时间间隔没有间隙。没有近似值。
请注意,如果您将 (msec, byte/msec) 的积分视为 (x,y) 的单位,则曲线下的面积是观察期间发送的字节数(确切地说)。无论观察结果如何切割,您都会得到相同的答案。(即:经常报告 2 倍)。
因此,通过简单地报告 (size_byte, start_ms,stop_ms),您只需将 (stop_ms-start_ms) 累积到时间中,并在每次观察时累积 size_byte 。如果您想将这些速率划分为分钟桶中的图表,那么只需维护每分钟(观察)的 (byte,ms) 对。
请注意,这些是个人转账的费率。个人传输可能会遇到 1MB/s(用户观点)。这些是您向最终用户保证的费率。
对于简单的情况,您可以将其留在这里。但是正确地计算,可以得到更多有趣的东西。
从服务器的角度来看,负载很重要。假设有两个用户同时体验 1MB/s。对于该统计数据,您需要减去重复计算的时间。如果 2 个用户在 1s 内同时进行 1MB/s,那么 1s 为 2MB/s。您需要有效地重建时间重叠,并减去重复计算的时间段。在传输结束时显式记录 (size_byte,start_ms,stop_ms) 允许您测量有趣的事情:
- 在任何给定时间的未完成传输的数量(队列长度分布 - 即:“我会用完内存吗?”)
- 作为传输次数函数的吞吐量(队列长度的吞吐量 - 即:“当我们的广告在电视上显示时网站是否崩溃?”)
- 利用率 - 即:“我们是否为我们的云提供商支付了过高的费用?”
在这种情况下,所有累积的计数器都是精确的整数运算。减去重复计算的时间会突然让您进入更复杂的算法(当有效和实时计算时)。