Я сравнивал производительность двух функций в консоли Chrome, когда наткнулся на то, что не могу объяснить.
const A = 3,
B = 2,
C = 4,
D = 2;
const mathCompare = (a1, a2, b1, b2) => {
return Math.abs(Math.log(a1/a2)) < Math.abs(Math.log(b1/b2));
};
const logicCompare = (a1, a2, b1, b2) => {
return (a1 > a2 ? a1/a2 : a2/a1) < (b1 > b2 ? b1/b2 : b2/b1);
};
const runLooped = (j) => {
for(let i = 0; i < 4; i++) {
jsCompare(mathCompare, logicCompare, j);
}
}
const jsCompare = (f1, f2, iterations) => {
let a = jsPerf(f1, iterations);
let b = jsPerf(f2, iterations);
console.warn( iterations + " iterations:\n" + f1.name + ": " + a + " ms\n" + f2.name + ": " + b + " ms\n" + "delta: " + (a-b) + " ms");
}
const jsPerf = (f, iterations) => {
let start = performance.now();
for(let i = 0; i < iterations; i++) {
f(A, B, C, D);
}
return performance.now() - start;
}
runLooped(10000000);
Запуск наборов
10M итераций
n раз:
- logicCompare () : все наборы take ~ 170ms
- mathCompare () : первый набор занимает ~ 14ms , следующие наборы занимают ~ 600ms .
Поскольку производительность изменилась только после полного набора итераций - одного вызова jsCompare () - я решил попробовать еще раз с менее расформированной структурой:
const A = 3,
B = 2,
C = 4,
D = 2;
const mathCompare = (a1, a2, b1, b2) => {
return Math.abs(Math.log(a1/a2)) < Math.abs(Math.log(b1/b2));
};
const logicCompare = (a1, a2, b1, b2) => {
return (a1 > a2 ? a1/a2 : a2/a1) < (b1 > b2 ? b1/b2 : b2/b1);
};
const compareRaw = (f1, f2, maxI, maxJ) => {
for(let i = 0; i < maxI; i++) {
let j,
a = performance.now();
for(j = 0; j < maxJ; j++) {
f1(A, B, C, D);
}
let b = performance.now();
for(j = 0; j < maxJ; j++) {
f2(A, B, C, D);
}
let c = performance.now();
console.warn( j + " iterations:\n" + f1.name + ": " + (b-a) + " ms\n" + f2.name + ": " + (c-b) + " ms\n" + "delta: " + ((b-a) - (c-b)) + " ms");
}
};
const runRaw = (i) => {
compareRaw(mathCompare, logicCompare, 4, i);
};
runRaw(10000000);
Совсем другой результат. Результаты стабилизируются в районе 3, после некоторых колебаний.
Chrome 79.0.3945.130:
- logicCompare () : все наборы занимают ~ 12 мс
- mathCompare () : все наборы занимают ~ 10 мс
Vivaldi 2.6.1566.49 (V8 7.5.288.30 ):
- logicCompare () : все наборы занимают ~ 60 мс
- mathCompare () : все наборы возьми ~ 10 мс
Я был заинтригован и попробовал все снова, но на этот раз со случайными числами. Проект, для которого я тестировал этот проект, очевидно, никогда не будет вызывать эти функции n * 10M раз с теми же параметрами.
const mathCompare = (a1, a2, b1, b2) => {
return Math.abs(Math.log(a1/a2)) < Math.abs(Math.log(b1/b2));
};
const logicCompare = (a1, a2, b1, b2) => {
return (a1 > a2 ? a1/a2 : a2/a1) < (b1 > b2 ? b1/b2 : b2/b1);
};
const compareRawRandom = (f1, f2, maxI, maxJ) => {
let randoms = [...Array(maxJ + 3)].map(()=>Math.floor(Math.random()*10));
for(let i = 0; i < maxI; i++) {
let j,
a = performance.now();
for(j = 0; j < maxJ; j++) {
f1(randoms[j], randoms[j + 1], randoms[j + 2], randoms[j + 3]);
}
let b = performance.now();
for(j = 0; j < maxJ; j++) {
f2(randoms[j], randoms[j + 1], randoms[j + 2], randoms[j + 3]);
}
let c = performance.now();
console.warn( j + " iterations:\n" + f1.name + ": " + (b-a) + " ms\n" + f2.name + ": " + (c-b) + " ms\n" + "delta: " + ((b-a) - (c-b)) + " ms");
}
}
const runRawRandom = (i) => {
compareRawRandom(mathCompare, logicCompare, 4, i);
};
const jsCompareRandom = (f1, f2, iterations) => {
let randoms = [...Array(iterations + 3)].map(()=>Math.floor(Math.random()*10));
let a = jsPerfRandom(f1, iterations, randoms);
let b = jsPerfRandom(f2, iterations, randoms);
console.warn( iterations + " iterations:\n" + f1.name + ": " + a + " ms\n" + f2.name + ": " + b + " ms\n" + "delta: " + (a-b) + " ms");
}
const jsPerfRandom = (f, iterations, randoms) => {
let start = performance.now();
for(let i = 0; i < iterations; i++) {
f(randoms[i], randoms[i + 1], randoms[i + 2], randoms[i + 3]);
}
return performance.now() - start;
}
const runRandomLooped = (j) => {
for(let i = 0; i < 4; i++) {
jsCompareRandom(mathCompare, logicCompare, j);
}
}
runRandomLooped(10000000);
runRawRandom(10000000);
runRandomLooped () показывает тот же самый странный низкий первый 10M, установленный для mathCompare ().
- logicCompare () : все наборы занимают ~ 280 мс
- mathCompare () : первый набор ~ 27ms , следующие наборы ~ 800ms
runRawRandom () менее разложенная версия, выполняющая точно такие же вычисления, однако снова стабилизируется после 2 комплектов по 10м. Но на этот раз обе функции показывают одинаковую производительность ~ 23 мс для вызовов 10M.
Это отображается только в браузерах Chrome / Chromium. Проверено на:
- Chrome 79.0.3945.130
- Vivaldi 2.6.1566.49 (используется V8 7.5.288.30)
Я также проверял на Firefox 72.0.2, которая показала постоянную производительность по сетам и обоим способам зацикливания.
- logicCompare () : ~ 110ms
- mathCompare () : ~ 35ms
Я использую AMD FX-8350 на текущей Win10.
Я думаю, это как-то связано с оптимизацией V8 во время выполнения, но я не ожидал, что производительность go в этом случае.