我采纳了Basil Bourque的回答后,重新思考了这个问题,并成功创建了一个具有以下优势的可行版本:
- 不需要过于频繁的计时钟任务:一个通常100毫秒左右的评估(±自然偏差)就足够了,不会有任何重置零的问题。
- 不再需要(昂贵的)Date对象:每进行一次“计数”操作时不必创建。
我没有尝试保留过去10秒内每一秒的独立历史值,而是改为创建了10个变量,这些变量连续累积10秒,起始自1秒偏移位。
因此,每秒我都有一个代表过去10秒的计数,易于重置零和计算。
- 有一个长度为10的数组,使用AtomicIntegers避免并发问题。
- 计时器每秒运行。
- 前10秒,将创建一个新的整数,加入数组。
- 进来的触发器将递增所有非空的数组位置。
- 前10秒,由
position 0
/ secondsPassed
评估。
- 第10秒后始终由
position p / 10.0
为所需平均。
代码(已去除了冗余部分):
private AtomicLong persistentCount = new AtomicLong(0);
private AtomicInteger[] messages = {new AtomicInteger(0), null, null, null, null, null, null, null, null};
private AtomicLong[] bytes = {new AtomicLong(0), null, null, null, null, null, null, null, null, null };
private boolean bufferFilled=false;
private int bf = 0;
private int p = 1;
private Timer timer = new Timer();
private TimerTask timerTask;
private PerformanceUtils(){
this.timerTask = new TimerTask() {
@Override
public void run() {
double mps, bps;
if (bf == 9){
mps = messages[p].getAndSet(0) / 10.0;
bps = bytes[p].getAndSet(0) / 10.0;
p++;
if (p == 10)
p=0;
}else{
mps = messages[0].get() / (p * 1.0);
bps = bytes[0].get() / (p * 1.0);
}
if (bf < 9){
messages[p] = new AtomicInteger(0);
bytes[p] = new AtomicLong(0);
p++;
bf++;
if (p == 10){
p=0;
}
}
//显示值
}
};
timer.schedule(timerTask, 100,1000);
}
public void notifyMessageReceived(long byteCount){
for (int i=0; i<=bf; i++){
messages[i].getAndAdd(1);
bytes[i].getAndAdd(byteCount);
}
persistentCount.getAndAdd(1);
}
[478, null, null, null, null, null, null, null, null] => [478, 0, null, null, null, null, null] => 478.0 [105, 527, null, null, null, null, null, null] => [105, 527 0, null, null, null, null] => 50.5 [1628, 1150, 623, null, null, null, null] => 1628, 115, 623 0, null, null] => 542.666666666666 [1767, 1289, 762, 139, null, null] => 1767, 1289, 762, 139 0, null] => 41.7 [1782, 1304, 777, 154, 15, null] => 178, 1304, 777, 154 15 0, null] => 35.4 [1807, 1329, 802, 179, 40 25, null] => 1807, 1329, 802, 179, 40 2 0, null] => 30.1666666666667 [1842, 1364, 837, 214 75 60 35, null] => 1842, 1364, 837, 214 75 60 35 0, null] => 26.314285714285717 [1869, 139, 864, 241, 102 87 62, 27, null] => 189, 139, 864, 241,102 8 62 62 2, null] => 23.625 [1896, 1418, 891, 268, 129 148, 12, 54, 27, null] => 1896, 141, 891,268 129 14 18 12 5,2 2, null] => 21.666666666666667 [1930, 1452, 925, 302 163 148 12 18, 15 8 141, 34] => 1930, 1452, 925,302 163 148 12 18 15 18 14
通过调试来看,它如预期一样,在运行10秒后,高峰期和低谷值的变动不再导致计算速率发生巨大变化,就像按每秒评估那样。
举一些因为夜间的小数字为例:
最初10秒:数组的"锁定"位置",评估"始终为0 / 时间">
[478, null, null, null, null, null, null, null, null, null]
=> [478, 0, null, null, null, null, null, null, null, null] => 478.0
[1005, 527, null, null, null, null, null, null, null, null]
=> [1005, 527, 0, null, null, null, null, null, null, null] => 502.5
[1628, 1150, 623, null, null, null, null, null, null, null]
=> [1628, 1150, 623, 0, null, null, null, null, null, null] => 542.6666666666666
[1767, 1289, 762, 139, null, null, null, null, null, null]
=> [1767, 1289, 762, 139, 0, null, null, null, null, null] => 441.75
[1782, 1304, 777, 154, 15, null, null, null, null, null]
=> [1782, 1304, 777, 154, 15, 0, null, null, null, null] => 356.4
[1807, 1329, 802, 179, 40, 25, null, null, null, null]
=> [1807, 1329, 802, 179, 40, 25, 0, null, null, null] => 301.1666666666667
[1842, 1364, 837, 214, 75, 60, 35, null, null, null]
=> [1842, 1364, 837, 214, 75, 60, 35, 0, null, null] => 263.14285714285717
[1869, 1391, 864, 241, 102, 87, 62, 27, null, null]
=> [1869, 1391, 864, 241, 102, 87, 62, 27, 0, null] => 233.625
[1896, 1418, 891, 268, 129, 114, 89, 54, 27, null]
=> [1896, 1418, 891, 268, 129, 114, 89, 54, 27, 0] => 210.66666666666666
[1930, 1452, 925, 302, 163, 148, 123, 88, 61, 34]
=>[0, 1452, 925, 302, 163, 148, 123, 88, 61, 34] => 193.0
从第10秒开始,总是评估最老的条目(大约10秒,真是意外)然后重置为0。
[48, 1500, 973, 350, 211, 196, 171, 136, 109, 82]
=> [48, 0, 973, 350, 211, 196, 171, 136, 109, 82] => 150.0
[62, 14, 987, 364, 225, 210, 185, 150, 123, 96]
=> [62, 14, 0, 364, 225, 210, 185, 150, 123, 96] => 98.7
[107, 59, 45, 409, 270, 255, 230, 195, 168, 141]
=> [107, 59, 45, 0, 270, 255, 230, 195, 168, 141] => 40.9
[134, 86, 72, 27, 297, 282, 257, 222, 195, 168]
=>[134, 86, 72, 27, 0, 282, 257, 222, 195, 168] => 29.7
[157, 109, 95, 50, 23, 305, 280, 245, 218, 191]
=> [157, 109, 95, 50, 23, 0, 280, 245, 218, 191] => 30.5
[188, 140, 126, 81, 54, 31, 311, 276, 249, 222]
=> [188, 140, 126, 81, 54, 31, 0, 276, 249, 222] => 31.1
[233, 185, 171, 126, 99, 76, 45, 321, 294, 267]
=> [233, 185, 171, 126, 99, 76, 45, 0, 294, 267] => 32.1
[258, 210, 196, 151, 124, 101, 70, 25, 319, 292]
=> [258, 210, 196, 151, 124, 101, 70, 25, 0, 292] => 31.9
[295, 247, 233, 188, 161, 138, 107, 62, 37, 329]
=> [295, 247, 233, 188, 161, 138, 107, 62, 37, 0] => 32.9
···
从未想过从实时数据中获取一个浮点平均值(且内存占用极少)竟然需要如此大的努力。