Для цикла медленнее, чем уменьшить?
Я получаю очень странные тайминги из этого кода. Иногда цикл for работает намного медленнее.
var len = 8e6
function *rands(){
for(let i =0; i < len; i++)
yield Math.random()
}
var add = (a,b) => a + b
var arr = new Float64Array([...rands()])
console.time('reduce')
var sum = arr.reduce(add)
console.log(sum)
console.timeEnd('reduce')
console.time('loop')
var sum = 0
for(let i = 0; i < len; i++)
sum += arr[i]
console.log(sum)
console.timeEnd('loop')
1 ответ
В первом примере вы даете компилятору V8 много подсказок о том, что это за тип, так что нет никаких проблем с боксом / распаковкой.
Немного измененная версия цикла for здесь. На моей машине цикл for теперь примерно в 5 раз быстрее, чем сокращение.
var len = 8e6
function *rands(){
for(let i =0; i < len; i++)
yield Math.random()
}
var add = (a,b) => a + b
var arr = new Float64Array([...rands()])
console.time('reduce')
var sum = arr.reduce(add)
console.log(sum)
console.timeEnd('reduce')
console.time('loop')
var sum = new Float64Array([0]);
for(var i = 0; i < len; i++)
sum[0] += arr[i];
console.log(sum[0])
console.timeEnd('loop')
Как вы видете sum[0] += arr[i];
Теперь компилятору V8 легко узнать, что в этом вычислении для добавления используется Float64, поскольку и левая, и правая стороны должны быть Float64.
Когда вы имели -> sum += arr[i]
правая сторона V8 знает, что это Float64, но левая сторона может быть чем угодно, может быть целым числом, строкой или даже Float64, поэтому V8 должен проверить, нужно ли помещать его в Float64.
С помощью Reduce, опять же, подразумевается, что левая и правая части функции add будут Float64, потому что механизм v8 перебирает массив Float64, a & b, который, как он знает, будет Float64.