Il riutilizzo degli oggetti ottimizza questa funzione spesso chiamata?

3

Supponiamo che io abbia una funzione che devo chiamare molto, forse qualche migliaio di volte su ogni mossa del mouse o del mouse. Usa un'istanza di una funzione (classe), chiamata Transform :

function func1(a, b, c) {
  var t = new Transform();
  t.rotate(a);
  t.scale(b, c);
  return t.m[0];
}

Quindi sto creando migliaia di nuove trasformazioni come chiamo func1 lotti.

Cosa succede se, invece di creare new Transform() s ogni volta, ho creato un piccolo sistema per allocare trasformazioni extra solo quando necessario e riutilizzarle:

window.Util = {
  _CachedTransforms: [],
  tempTransform: function() {
    var arr = Util._CachedTransforms;
    var temp = arr.pop();
    if (temp === undefined) return new Transform();
    return temp;
  },
  freeTransform: function(temp) {
    Util._CachedTransforms.push(temp);
  }
}

Quindi potrei chiamare func2 :

function func2(a, b, c) {
  var t = Util.tempTransform();
  t.reset();
  t.rotate(a);
  t.scale(b, c);
  var result = t.m[0];
  Util.freeTransform(t);
  return result;
}

Usando func2 diverse migliaia di volte, new Transform viene sempre chiamato solo una volta. Questo potrebbe suggerire un vantaggio, ma i numeri di jsperf non sembrano suggerire alcuno.

Se vuoi vedere queste due funzioni in azione e la classe Transform, dai un'occhiata a jsperf: link

E soprattutto: link

Per simulare che si verifichi un sacco durante un evento, il mio test di jsperf fa:

var a;
for (var i = 0; i < 4000; i++) {
  a += func1(1, i, 3); // vs func2
}

Potrebbero esserci modi migliori per testare se questo è vantaggioso o meno. Mi manca qualcosa?

Più in generale, il riutilizzo di oggetti come questo è ancora una buona idea in questo scenario, o mai?

    
posta Simon Sarris 12.07.2013 - 19:22
fonte

4 risposte

1

Questo è un metodo noto come "pooling di oggetti" , e tu sei correggi che può velocizzare le prestazioni. La creazione di oggetti è in genere un'attività piuttosto economica in Javascript (anche se Object.create può essere piuttosto lento sorprendentemente nella mia esperienza), ma la necessità di invocare ripetutamente il GC può causare notevoli problemi di prestazioni.

Ovviamente, devi solo ottimizzare se hai figure che suggeriscono che devi.

Sono un po 'sulla stessa pagina di Avner Shahar-Kashtan in quella creazione di oggetti che potrebbe non essere nemmeno richiesto in questo caso.

    
risposta data 30.07.2014 - 15:56
fonte
7

C'è un motivo per cui hai bisogno di più oggetti Transform? Non sarebbe più semplice avere Transform senza stato e avere i metodi rotate e scale semplicemente restituire un oggetto trasformato? In questo modo non devi preoccuparti dello stato di Transform e puoi generare in modo sicuro ciascuna funzione su un thread diverso, il che potrebbe portare a miglioramenti significativi.

    
risposta data 12.07.2013 - 20:11
fonte
1

Ridurre il tempo impiegato per allocare gli oggetti è una buona idea. È così bello che la maggior parte delle implementazioni di javascript lo stanno già facendo dietro le quinte. Quindi, quando provi ad implementare la tua versione, devi solo implementare una versione meno efficiente di quella che il runtime ti sta già dando.

È possibile migliorare le prestazioni non allocando oggetti. Tuttavia, il tuo metodo essenzialmente sta ancora assegnando gli oggetti, hai appena implementato un allocatore personalizzato. Probabilmente non puoi battere l'allocatore già disponibile in una buona implementazione javascript.

    
risposta data 12.07.2013 - 20:13
fonte
0

Considerato che Javascript è a thread singolo, non è utile mantenere una matrice di più istanze, poiché in un dato momento può essere presente solo un oggetto Transform in uso. Inoltre, poiché l'utilizzo dell'oggetto tranform è sincrono, non è necessario bloccare / liberare l'istanza. Quindi, in effetti, hai solo bisogno di una istanza, che può essere resa globale, risparmiandoti ulteriori chiamate di funzione.

function func2(a, b, c) {
  var t = Window.transformSingleton;
  t.reset();
  t.rotate(a);
  t.scale(b, c);
  var result = t.m[0];
  return result;
}

Un'altra opzione sarebbe passare l'oggetto di trasformazione come parametro a func2 . Gli argomenti oggetto Javascript vengono passati come riferimenti, quindi stai ancora utilizzando un singolo oggetto.

    
risposta data 27.05.2015 - 18:13
fonte

Leggi altre domande sui tag