最终编辑:我错了。 Redis文档中没有任何内容表明计数器只能达到255,即大约一百万。仅在达到100万次点击时,计数器位于255。案例已结案。不用再看了。
我正在尝试将Redis' LFU algorithm从C移植到JS。它使用莫里斯计数器。
常量:
LFU_INIT_VAL = 5
。见过here。
lfu_log_factor = 10
。看过here
找到here的C函数。
/* Logarithmically increment a counter. The greater is the current counter value
* the less likely is that it gets really implemented. Saturate it at 255. */
uint8_t LFULogIncr(uint8_t counter) {
if (counter == 255) return 255;
double r = (double)rand()/RAND_MAX;
double baseval = counter - LFU_INIT_VAL;
if (baseval < 0) baseval = 0;
double p = 1.0/(baseval*server.lfu_log_factor+1);
if (r < p) counter++;
return counter;
}
我的JS端口:
LFU_INIT_VAL = 5
lfu_log_factor = 10
function LFULogIncr(counter) {
if (counter == 255) return 255;
let r = Math.random();
let baseval = counter - LFU_INIT_VAL;
if (baseval < 0) baseval = 0;
let p = 1.0/(baseval*lfu_log_factor+1);
if (r < p) counter++;
return counter;
}
运行算法一百万次,并在计数器增加时记录迭代索引:
let hitFreq = 5
for (let i = 0; i < 1000000; i++) {
let newHitFreq = LFULogIncr(hitFreq)
if (newHitFreq > hitFreq) {
console.log(`New counter: ${newHitFreq}, i = ${i}`)
}
hitFreq = newHitFreq
}
基于此表,可以在链接中找到...
+--------+------------+------------+------------+------------+------------+
| factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits |
+--------+------------+------------+------------+------------+------------+
| 0 | 104 | 255 | 255 | 255 | 255 |
+--------+------------+------------+------------+------------+------------+
| 1 | 18 | 49 | 255 | 255 | 255 |
+--------+------------+------------+------------+------------+------------+
| 10 | 10 | 18 | 142 | 255 | 255 |
+--------+------------+------------+------------+------------+------------+
| 100 | 8 | 11 | 49 | 143 | 255 |
+--------+------------+------------+------------+------------+------------+
根据上表,在lfu_log_factor
为10的情况下,当达到100万次点击时,计数器应为255。但是,当运行我的JS代码时,计数器在约30万次点击中始终达到255。我在做什么错了?
这是一次JS代码运行的结果,将实际匹配数与预期匹配数(factor
为10 :)进行了比较:
New counter: 10, i = 149
(预计〜100,超过49)New counter: 18, i = 652
(预计〜1000,低于348)New counter: 142, i = 96383
(预计为100k,低于3617)New counter: 255, i = 275361
(预计〜1M,低于724,639 !!!)编辑:嗯...我在C语言中得到的结果与在JS中相同。 255的计数器命中约30万次。
https://onlinegdb.com/Sy8Y8-SJN
表格错误/过时,或者我进行的测试错误,或者代码正确,或者我误解了结果。