Momentan kämpfe ich mit einem sehr seltsamen Leistungsproblem. Der Durchschnitt für den SlowHeap beträgt 1448.623 ms, während der FastHeap nur 550.425 ms benötigt. Ich habe es mehrmals betrachtet, aber der einzige Unterschied zwischen den beiden ist, dass der erste ein "undefined" Element am Anfang von _arr verwendet und der zweite nicht. Aber sie machen beide die gleichen Operationen und so weiter. Das habe ich mit dem Code darunter verifiziert.Merkwürdiges JavaScript/Node.js Performance-Problem
Gibt es jemanden, der ein Licht auf dieses Problem werfen könnte?
let slowHeapOperationCount = 0
let fastHeapOperationCount = 0
let slowHeapExchanged = []
let fastHeapExchanged = []
function SlowHeap(cmp = (a, b) => a > b ? 1 : a < b ? -1 : 0) {
this.cmp = cmp
this._arr = [undefined]
this.size = 0
}
function FastHeap(cmp = (a, b) => a > b ? 1 : a < b ? -1 : 0) {
this.cmp = cmp
this._arr = []
this.size = 0
}
SlowHeap.prototype.bubbleUp = function (cmp, _arr, val) {
let idxNr = this.size, parentIdxNr = idxNr >> 1
while (idxNr > 0 && cmp(_arr[parentIdxNr], val) > 0) {
slowHeapExchanged.push([_arr[parentIdxNr], val])
_arr[idxNr] = _arr[parentIdxNr]
_arr[parentIdxNr] = val
idxNr = parentIdxNr
parentIdxNr = idxNr >> 1
slowHeapOperationCount++
}
}
FastHeap.prototype.bubbleUp = function (cmp, _arr, val) {
var idxNr = this.size,
parentIdxNr = ((idxNr - 1)/2) | 0;
while (idxNr > 0 && cmp(_arr[parentIdxNr], val) > 0) {
fastHeapExchanged.push([_arr[parentIdxNr], val])
_arr[idxNr] = _arr[parentIdxNr];
_arr[parentIdxNr] = val;
idxNr = parentIdxNr;
parentIdxNr = ((idxNr - 1)/2) | 0;
fastHeapOperationCount++
}
}
SlowHeap.prototype.push = function (val) {
++this.size
this._arr.push(val)
this.bubbleUp(this.cmp, this._arr, val)
return this.size
}
FastHeap.prototype.push = function (val) {
this._arr.push(val);
this.bubbleUp(this.cmp, this._arr, val);
return ++this.size;
}
const itemCount = 4000000
const slowHeap = new SlowHeap()
const fastHeap = new FastHeap()
//
// Append the same Number Collection to each Heap:
const numberCollection = []
for (let idxNr = 0; idxNr < itemCount; idxNr++) numberCollection.push(Math.random())
//
// Benchmark for the Slow Heap:
console.time('SlowHeap')
for (let idxNr = 0; idxNr < itemCount; idxNr++) {
slowHeap.push(numberCollection[idxNr])
}
console.timeEnd('SlowHeap')
//
// Benchmark for the Fast Heap:
console.time('FastHeap')
for (let idxNr = 0; idxNr < itemCount; idxNr++) {
fastHeap.push(numberCollection[idxNr])
}
console.timeEnd('FastHeap')
//
// Verify the "_arr" from the Slow Heap against the Fast Heap:
for (let idxNr = 0; idxNr < itemCount; idxNr++) {
if (slowHeap._arr[idxNr + 1] !== fastHeap._arr[idxNr]) console.log('Unequal value found!')
}
if (slowHeapExchanged.length !== fastHeapExchanged.length) console.log('Help! Comp. is not equal.')
for (let idxNr = 0, maxNr = slowHeapExchanged.length; idxNr < maxNr; idxNr++) {
if (slowHeapExchanged[idxNr][0] !== fastHeapExchanged[idxNr][0] || slowHeapExchanged[idxNr][1] !== fastHeapExchanged[idxNr][1]) {
console.log('Help!')
}
}
console.log(slowHeapOperationCount)
console.log(fastHeapOperationCount)
Das ist nicht nur eine Vermutung, V8 ist dafür bekannt, Arrays von 'double's unboxed zu halten – Bergi
Danke! Ich habe nachgesehen und es scheint richtig zu sein. https://github.com/thlorenz/v8-perf/blob/master/data-types.md#double-array-unboxing enthält weitere Informationen zum Thema. Ich sollte das auf jeden Fall etwas genauer untersuchen, denn der Grund, warum ich das "undefined" benutzt habe, war im ersten Fall für die Performance. –