Для цикла медленнее, чем уменьшить? - PullRequest
0 голосов
/ 21 ноября 2018

Я получаю очень странные тайминги из этого кода.Иногда цикл 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 Ответ

0 голосов
/ 22 ноября 2018

В вашем первом примере вы даете компилятору 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.

...