0

私は、キャンバスにペイントする反復プロセスでパフォーマンスを向上させるために使用した、JavaScriptの奇妙なテクニックに気付きました。非同期スケジューラのパフォーマンスを最大化する方法は?

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>

あなた混乱した場合:将来的には、私は彼らが実装されますが、その間に、これは私が使用して何のための一般的な考え方であるとなっSharedBuffferあるいはSharedCanvasを使用する予定パラメータの周りには、もちろんdelayintervalsの両方がパフォーマンスに大きな違いをもたらすことがわかります。しかし、ある一定の遅延に対してあまりにも多くのintervalsを設定すると、パフォーマンスの低下がパフォーマンス低下に変わり、スレッドが応答しなくなります。

私の質問は、someExpensiveFunctionに基づいてintervalsdelayを適応的に選択できますか? someExpensiveFunction()は、高解像度のタイムスタンプ、performance.now()を返すことができると仮定しましょう。どのようにしてintervalsdelayを最適化してパフォーマンスを最適化できますか?

+0

あなたは間隔の期間は、時間の経過とともに変化することができるように、のsetIntervalの代わりにsetTimeoutを使用したいと思います。また、setTimeoutを適切に使用すると、一度に多くの操作を積み重ねることができなくなります。 (setIntervalのロジックがインターバルを超えていれば、あなたは困っているでしょう) –

+0

@ChristopherDaviesもしあなたが望むなら、 'setTimeout'を使うようにスケジューラを書き直すことはできますが、それは本当に私の主な質問に答えません最適な値をプログラムで指定します。また、 'setInterval'のロジックがインターバルを超えた場合、慎重に行うと、パフォーマンスが向上します。私の推測では、JavaScriptエンジンはCPUに何らかの理由でCPUにオーバークロックなどを促しているが、ヒントとして試してみると、さまざまなコンピュータとブラウザで特定の値が異なることになる。 –

+0

ここにsetTimeoutを使うべき理由があります:https://zetafleet.com/blog/2010/04/why-i-consider-setinterval-to-be-harmful.htmlあなたの主要な質問については、フォローアップのコメントを投稿します。 –

答えて

0

これはウェブワーカーを使用する絶好の機会のようです。それらは別のスレッドで実行されるため、メインスレッドのアニメーションには影響しません。

しかし、依然としてpostMessageをあまり頻繁に使用しないでください。また、メインスレッドのイベントループが、膨大な数のメッセージを刻むことがあります。

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

私は以前にウェブワーカーを使用しました。ボトルネックは、メッセージが積み重なり、生成されている間にすぐにDOMスレッドにディスパッチされないということになります。 –

+0

これは、reportPerSecの理由です。これは、イベントループを過負荷にしているWebワーカーではないシナリオと同じ問題です。それを除いて、あなたはまた、主な内容のコードを持っています。 – Cine

関連する問題