0

Ich habe eine seltsame Technik in JavaScript bemerkt, die ich verwendet habe, um die Leistung in sich wiederholenden Prozessen zu erhöhen, die auf einer Leinwand malen. In Zukunft plane ich ein SharedBufffer oder sogar ein SharedCanvas zu verwenden, wenn sie umgesetzt werden, aber in der Zwischenzeit, das ist die allgemeine Idee für das, was ich benutze:Wie maximiert man die Leistung eines asynchronen Schedulers?

function someContinuousProcess(intervals, delay) { 
 
    var count = 0; 
 
    var span = document.querySelector('span'); 
 

 
    function someExpensiveFunction() { 
 
    if (count >= 1e9) { 
 
     return false; 
 
    } 
 

 
    do { 
 
     count++; 
 
    } while (count % 1e5); 
 

 
    span.textContent = count; 
 
    
 
    return true; 
 
    } 
 
    
 
    function wrapper(index) { 
 
    var start = performance.now(); 
 
    
 
    if (someExpensiveFunction()) { 
 
     var delta = performance.now() - start; 
 
     // some logic here to determine new 
 
     // values for `intervals` and `delay` 
 
     scheduler[index] = setTimeout(
 
     wrapper.bind(null, index), 
 
     delay 
 
    ); 
 
    } 
 
    } 
 

 
    var scheduler = []; 
 

 
    function startScheduler() { 
 
    for (var i = 0; i < intervals; i++) { 
 
     scheduler[i] = setTimeout(
 
     wrapper.bind(null, i), 
 
     delay 
 
    ); 
 
    } 
 
    } 
 

 
    function stopScheduler() { 
 
    for (var i = 0; i < scheduler.length; i++) { 
 
     clearTimeout(scheduler[i]); 
 
    } 
 

 
    scheduler = []; 
 
    } 
 

 
    startScheduler(); 
 
} 
 

 
int.onchange = del.onchange =() => { 
 
    var intervals = parseInt(int.value); 
 
    var delay  = parseInt(del.value); 
 

 
    if (!isNaN(intervals) && !isNaN(delay)) { 
 
    someContinuousProcess(intervals, delay); 
 
    } 
 
};
<input placeholder=intervals id=int> 
 
<input placeholder=delay id=del> 
 
<span></span>

Wenn Sie Schlamassel um mit den Parametern, werden Sie feststellen, dass natürlich delay und intervals beide einen signifikanten Unterschied in der Leistung machen. Aber zu einem bestimmten Punkt, wenn Sie zu viele intervals für eine bestimmte Verzögerung festlegen, wird die Leistungssteigerung zu einem Leistungsabfall, zusammen mit dem Rendern des Threads nicht mehr reagieren.

Meine Frage ist, ist es möglich, intervals und delay basierend auf einem gegebenen someExpensiveFunction adaptiv auszuwählen? Lassen Sie uns annehmen, dass wir someExpensiveFunction() eine hohe Auflösung Zeitstempel, performance.now() zurückgeben können, wie können wir dann verwenden, um intervals und delay intelligent zu variieren, um die Leistung zu optimieren?

+0

Sie wollen würde SetTimeout statt setInterval, verwenden, so dass die Dauer des Intervalls im Laufe der Zeit ändern können. Außerdem verhindert die Verwendung von setTimeout, dass Sie viele Operationen gleichzeitig stapeln. (Wenn Ihre Logik in setInterval das Intervall überschreitet, werden Sie in Schwierigkeiten geraten.) –

+0

@ChristopherDavies Ich kann den Scheduler so umschreiben, dass er 'setTimeout' verwendet, wenn Sie das bevorzugen, aber das beantwortet meine Hauptfrage nicht richtig programmatisch die optimalen Werte finden. Wenn die Logik in 'setInterval' das Intervall überschreitet, verbessert dies die Leistung, wenn Sie dies sorgfältig tun. Meine Vermutung ist, dass die JavaScript-Engine die CPU irgendwie zum Übertakten oder etwas unter diesen Bedingungen auffordert, aber während ich versuchte, Hinweise zu geben, werden die einzelnen Werte zwischen verschiedenen Computern und Browsern unterschiedlich sein. –

+0

Hier ist ein ziemlich guter Link, warum Sie setTimeout verwenden sollten: https://zetafleet.com/blog/2010/04/why-i-consider-setinterval-to-be-harmful.html Was Ihre primäre Frage betrifft, ich ' Ich werde einen Follow-up-Kommentar veröffentlichen. –

Antwort

0

Dies scheint die perfekte Gelegenheit, Webworker zu verwenden. Sie werden in einem separaten Thread ausgeführt, sodass sie keine Auswirkungen auf Animationen im Hauptthread haben.

Allerdings ist es immer noch erforderlich, dass Sie nicht postMessage zu oft, oder die Ereignisschleife im Haupt Thread Drosseln auf die schiere Anzahl der Nachrichten.

function simple() { 
 
    var span = $('#v1'); 
 
    var worker = new Worker('data:text/javascript;charset=UTF-8,' + encodeURI($('#someExpensiveFunction').text())); 
 

 
    worker.onmessage = progress => span.text(progress.data); 
 
    worker.onerror = x => { 
 
debugger; 
 
    }; 
 
} 
 

 
function withanim() { 
 
    var span = $('#v2'); 
 
    var worker = new Worker('data:text/javascript;charset=UTF-8,' + encodeURI($('#someExpensiveFunction').text())); 
 

 
    var latestMessage = 0; 
 
    worker.onmessage = progress => latestMessage = progress.data; 
 
    worker.onerror = x => { 
 
debugger; 
 
    }; 
 

 
    var myReq; 
 
    function step(timestamp) { 
 
span.text(latestMessage); 
 
if (latestMessage < 1e9) 
 
    myReq = requestAnimationFrame(step); 
 
    } 
 
    myReq = requestAnimationFrame(step); 
 
} 
 

 
simple(); 
 
withanim();
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js" 
 
type="text/javascript" charset="utf-8"></script> 
 
<div id=v1></div> 
 
<div id=v2></div> 
 
<script type="text/worker" id="someExpensiveFunction"> 
 
var count = 0; 
 
var start = performance.now(); 
 
var reportPerSec = 100; //change this 
 
var delay = 1000/reportPerSec; 
 
do { 
 
    //some un-interrupable task 
 
    //it might be useful to put this in a setTimeout(0), if you also want to use onmessage to get data to work on from the main thread 
 
do { 
 
count++; 
 
    } while (count % 1e2); 
 
    
 
    //report progress 
 
    if (performance.now() - start > delay) { 
 
    \t postMessage(count); 
 
start = performance.now(); 
 
    } 
 
} while (count < 1e9); 
 
postMessage(count); //make sure to send 'done' 
 
</script>

Fiddle

+0

Ich habe Web-Worker vorher verwendet. Der Engpass besteht darin, dass die Nachrichten sich stapeln und nicht so schnell an den DOM-Thread gesendet werden, wie sie generiert werden.Ich bin sicher, dass diese Antwort für andere nützlich sein kann, obwohl –

+0

Also der Grund für den ReportPerSec. Es ist das gleiche Problem, das Sie im Nicht-Web-Worker-Szenario haben, in dem Sie die Ereignisschleife überlasten. Außer dort haben Sie auch den Hauptcode zum Inhalt mit. – Cine

Verwandte Themen