質問
JavaScriptでマルチスレッドを実行する方法はありますか?
解決
見る http://caniuse.com/#search=worker 最新のサポート情報については、
以下は2009年頃のサポート状況です。
グーグルで検索したい言葉は、 JavaScript ワーカー スレッド
とは別に 歯車 現時点では利用可能なものはありませんが、これを実装する方法についてはたくさんの議論があるため、答えは間違いなく将来変わるので、この質問に注目してください。
Gears の関連ドキュメントは次のとおりです。 ワーカープールAPI
WHATWG には、ワーカー スレッドに関する推奨草案があります。 ウェブワーカー
Mozilla のものもある DOM ワーカー スレッド
アップデート: 2009 年 6 月、JavaScript スレッドに対するブラウザのサポートの現状
Firefox 3.5 ウェブワーカーがいます。Web ワーカーの動作を確認したい場合は、Web ワーカーのデモをいくつかご覧ください。
- 焼き鈍し法 (「試してみる」リンク)
- スペースインベーダーズ (リンクは投稿の最後にあります)
- MoonBat JavaScript ベンチマーク (最初のリンク)
Gears プラグインは Firefox にもインストールできます。
サファリ4, 、 そしてその WebKit ナイトリー ワーカースレッドがあります:
クロム Gears が組み込まれているため、ユーザーからの確認プロンプトが必要ですが、スレッドを実行できます (また、Gears プラグインがインストールされているどのブラウザでも動作しますが、Web ワーカーとは異なる API を使用します)。
- Google Gears WorkerPool デモ (Chrome や Firefox でテストするには実行速度が速すぎるため、良い例ではありませんが、IE の実行速度は対話をブロックしていることが確認できるほど遅いです)
IE8 そして IE9 Gears プラグインがインストールされている場合のみスレッドを実行できます
他のヒント
JavaScript でマルチスレッドと非同期を実行する別の方法
HTML5 より前の JavaScript では、ページごとに 1 つのスレッドしか実行できませんでした。
非同期実行をシミュレートするハッキングな方法がありました 収率, setTimeout()
, setInterval()
, XMLHttpRequest
または イベントハンドラ (例については、この投稿の最後を参照してください) 収率 そして setTimeout()
).
しかし、HTML5 では、ワーカー スレッドを使用して関数の実行を並列化できるようになりました。ここでは使用例を示します。
リアルマルチスレッド
マルチスレッド:JavaScript ワーカー スレッド
HTML5 Web ワーカー スレッドの導入 (以下を参照) ブラウザの互換性)
注記:IE9以前のバージョンではサポートされていません。
これらのワーカー スレッドは、ページのパフォーマンスに影響を与えることなくバックグラウンドで実行される JavaScript スレッドです。詳細については、 ウェブワーカー ドキュメントを読む または このチュートリアル.
以下は、MAX_VALUE までカウントし、現在の計算値をページに表示する 3 つの Web ワーカー スレッドを使用した簡単な例です。
//As a worker normally take another JavaScript file to execute we convert the function in an URL: http://stackoverflow.com/a/16799132/2576706
function getScriptPath(foo){ return window.URL.createObjectURL(new Blob([foo.toString().match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1]],{type:'text/javascript'})); }
var MAX_VALUE = 10000;
/*
* Here are the workers
*/
//Worker 1
var worker1 = new Worker(getScriptPath(function(){
self.addEventListener('message', function(e) {
var value = 0;
while(value <= e.data){
self.postMessage(value);
value++;
}
}, false);
}));
//We add a listener to the worker to get the response and show it in the page
worker1.addEventListener('message', function(e) {
document.getElementById("result1").innerHTML = e.data;
}, false);
//Worker 2
var worker2 = new Worker(getScriptPath(function(){
self.addEventListener('message', function(e) {
var value = 0;
while(value <= e.data){
self.postMessage(value);
value++;
}
}, false);
}));
worker2.addEventListener('message', function(e) {
document.getElementById("result2").innerHTML = e.data;
}, false);
//Worker 3
var worker3 = new Worker(getScriptPath(function(){
self.addEventListener('message', function(e) {
var value = 0;
while(value <= e.data){
self.postMessage(value);
value++;
}
}, false);
}));
worker3.addEventListener('message', function(e) {
document.getElementById("result3").innerHTML = e.data;
}, false);
// Start and send data to our worker.
worker1.postMessage(MAX_VALUE);
worker2.postMessage(MAX_VALUE);
worker3.postMessage(MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
3 つのスレッドが並行して実行され、ページに現在の値が出力されていることがわかります。これらは分離されたスレッドを使用してバックグラウンドで実行されるため、ページがフリーズすることはありません。
マルチスレッド:複数の iframe を使用する
これを達成するもう 1 つの方法は、複数の iframe, 、それぞれがスレッドを実行します。私たちが与えることができるのは、 iframe URL と iframe 結果を取得して出力するために親と通信できます ( iframe 同じドメイン内にある必要があります)。
この例はすべてのブラウザで動作するわけではありません。 iframe 通常、メイン ページと同じスレッド/プロセスで実行されます (ただし、Firefox と Chromium では処理が異なるようです)。
コード スニペットは複数の HTML ファイルをサポートしていないため、ここではさまざまなコードのみを提供します。
インデックス.html:
//The 3 iframes containing the code (take the thread id in param)
<iframe id="threadFrame1" src="thread.html?id=1"></iframe>
<iframe id="threadFrame2" src="thread.html?id=2"></iframe>
<iframe id="threadFrame3" src="thread.html?id=3"></iframe>
//Divs that shows the result
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
<script>
//This function is called by each iframe
function threadResult(threadId, result) {
document.getElementById("result" + threadId).innerHTML = result;
}
</script>
スレッド.html:
//Get the parameters in the URL: http://stackoverflow.com/a/1099670/2576706
function getQueryParams(paramName) {
var qs = document.location.search.split('+').join(' ');
var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g;
while (tokens = re.exec(qs)) {
params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
}
return params[paramName];
}
//The thread code (get the id from the URL, we can pass other parameters as needed)
var MAX_VALUE = 100000;
(function thread() {
var threadId = getQueryParams('id');
for(var i=0; i<MAX_VALUE; i++){
parent.threadResult(threadId, i);
}
})();
マルチスレッドをシミュレートする
シングルスレッド:setTimeout() を使用して JavaScript の同時実行性をエミュレートする
「単純な」方法は、関数を実行することです setTimeout()
次のように次々に:
setTimeout(function(){ /* Some tasks */ }, 0);
setTimeout(function(){ /* Some tasks */ }, 0);
[...]
しかし、この方法は 動作しません 各タスクが次々に実行されるためです。
次のように関数を再帰的に呼び出すことで、非同期実行をシミュレートできます。
var MAX_VALUE = 10000;
function thread1(value, maxValue){
var me = this;
document.getElementById("result1").innerHTML = value;
value++;
//Continue execution
if(value<=maxValue)
setTimeout(function () { me.thread1(value, maxValue); }, 0);
}
function thread2(value, maxValue){
var me = this;
document.getElementById("result2").innerHTML = value;
value++;
if(value<=maxValue)
setTimeout(function () { me.thread2(value, maxValue); }, 0);
}
function thread3(value, maxValue){
var me = this;
document.getElementById("result3").innerHTML = value;
value++;
if(value<=maxValue)
setTimeout(function () { me.thread3(value, maxValue); }, 0);
}
thread1(0, MAX_VALUE);
thread2(0, MAX_VALUE);
thread3(0, MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
ご覧のとおり、この 2 番目の方法は関数の実行にメイン スレッドを使用するため、非常に遅く、ブラウザがフリーズします。
シングルスレッド:JavaScript の同時実行性を yield でエミュレートする
収率 の新機能です ECMAScript 6, 、Firefox と Chrome の最も古いバージョンでのみ動作します (Chrome では有効にする必要があります) 実験的なJavaScript に登場する chrome://flags/#enable-javascript-harmony).
yield キーワードを指定すると、ジェネレーター関数の実行が一時停止され、yield キーワードに続く式の値がジェネレーターの呼び出し元に返されます。これは、return キーワードのジェネレータベースのバージョンと考えることができます。
ジェネレーターを使用すると、関数の実行を一時停止し、後で再開することができます。ジェネレーターを使用すると、と呼ばれる手法で関数をスケジュールできます。 トランポリン.
以下に例を示します。
var MAX_VALUE = 10000;
Scheduler = {
_tasks: [],
add: function(func){
this._tasks.push(func);
},
start: function(){
var tasks = this._tasks;
var length = tasks.length;
while(length>0){
for(var i=0; i<length; i++){
var res = tasks[i].next();
if(res.done){
tasks.splice(i, 1);
length--;
i--;
}
}
}
}
}
function* updateUI(threadID, maxValue) {
var value = 0;
while(value<=maxValue){
yield document.getElementById("result" + threadID).innerHTML = value;
value++;
}
}
Scheduler.add(updateUI(1, MAX_VALUE));
Scheduler.add(updateUI(2, MAX_VALUE));
Scheduler.add(updateUI(3, MAX_VALUE));
Scheduler.start()
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
JavaScript には真のスレッド機能はありません。JavaScript は柔軟な言語なので、その一部をエミュレートすることができます。ここにあります 例 先日、出会ってしまいました。
JavaScript には真のマルチスレッドはありませんが、次を使用して非同期動作を実現できます。 setTimeout()
および非同期 AJAX リクエスト。
いったい何を達成しようとしているのでしょうか?
ここに一つの方法があります シミュレートする JavaScriptでのマルチスレッド化
ここで、数値の加算を計算する 3 つのスレッドを作成します。数値は 13 で割ることができ、数値は 10000000000 まで 3 で割ることができます。そして、これら 3 つの関数は、同時実行が意味するように同時に実行することはできません。ただし、これらの関数を同時に再帰的に実行するトリックを紹介します。 jsフィドル
このコードは私のものです。
体の部分
<div class="div1">
<input type="button" value="start/stop" onclick="_thread1.control ? _thread1.stop() : _thread1.start();" /><span>Counting summation of numbers till 10000000000</span> = <span id="1">0</span>
</div>
<div class="div2">
<input type="button" value="start/stop" onclick="_thread2.control ? _thread2.stop() : _thread2.start();" /><span>Counting numbers can be divided with 13 till 10000000000</span> = <span id="2">0</span>
</div>
<div class="div3">
<input type="button" value="start/stop" onclick="_thread3.control ? _thread3.stop() : _thread3.start();" /><span>Counting numbers can be divided with 3 till 10000000000</span> = <span id="3">0</span>
</div>
JavaScript 部分
var _thread1 = {//This is my thread as object
control: false,//this is my control that will be used for start stop
value: 0, //stores my result
current: 0, //stores current number
func: function () { //this is my func that will run
if (this.control) { // checking for control to run
if (this.current < 10000000000) {
this.value += this.current;
document.getElementById("1").innerHTML = this.value;
this.current++;
}
}
setTimeout(function () { // And here is the trick! setTimeout is a king that will help us simulate threading in javascript
_thread1.func(); //You cannot use this.func() just try to call with your object name
}, 0);
},
start: function () {
this.control = true; //start function
},
stop: function () {
this.control = false; //stop function
},
init: function () {
setTimeout(function () {
_thread1.func(); // the first call of our thread
}, 0)
}
};
var _thread2 = {
control: false,
value: 0,
current: 0,
func: function () {
if (this.control) {
if (this.current % 13 == 0) {
this.value++;
}
this.current++;
document.getElementById("2").innerHTML = this.value;
}
setTimeout(function () {
_thread2.func();
}, 0);
},
start: function () {
this.control = true;
},
stop: function () {
this.control = false;
},
init: function () {
setTimeout(function () {
_thread2.func();
}, 0)
}
};
var _thread3 = {
control: false,
value: 0,
current: 0,
func: function () {
if (this.control) {
if (this.current % 3 == 0) {
this.value++;
}
this.current++;
document.getElementById("3").innerHTML = this.value;
}
setTimeout(function () {
_thread3.func();
}, 0);
},
start: function () {
this.control = true;
},
stop: function () {
this.control = false;
},
init: function () {
setTimeout(function () {
_thread3.func();
}, 0)
}
};
_thread1.init();
_thread2.init();
_thread3.init();
この方法がお役に立てば幸いです。
使用できます 物語的なJavaScript, 、コードをステート マシンに変換するコンパイラで、スレッド化を効果的にエミュレートできるようにします。これは、単一の線形コード ブロックで非同期コードを記述できるようにする「譲歩」演算子 (「->」と表記) を言語に追加することによって実現されます。
新しいv8エンジンは、 出てくるはずです 今日はそれをサポートしています(私はそう思います)
生の Javascript では、いくつかの非同期呼び出し (xmlhttprequest) を使用するのが最善ですが、それは実際にはスレッドではなく、非常に制限されています。 Google ギア ブラウザに多数の API を追加します。その一部はスレッドのサポートに使用できます。
AJAX を使用できない、または使用したくない場合は、iframe または ten! を使用してください。;) クロスブラウザ間の比較問題や、ドットネット AJAX などの構文の問題を心配することなく、マスター ページと並行して iframe でプロセスを実行でき、マスター ページの JavaScript (インポートされた JavaScript を含む) をiフレーム。
たとえば、親 iframe で次のように呼び出すと、 egFunction()
iframe コンテンツが読み込まれた後の親ドキュメント内 (これは非同期部分です)
parent.egFunction();
必要に応じて、メインの HTML コードから iframe を動的に生成することもできます。
JavaScript にはスレッドがありませんが、ワーカーはあります。
共有オブジェクトが必要ない場合は、ワーカーが良い選択になる可能性があります。
ほとんどのブラウザ実装では、実際にはワーカーがすべてのコアに分散され、すべてのコアを利用できるようになります。これのデモを見ることができます ここ.
というライブラリを開発しました タスク.js これにより、これが非常に簡単になります。
タスク.js CPU を大量に使用するコードをすべてのコア (node.js および Web) で実行するための簡素化されたインターフェイス
例としては
function blocking (exampleArgument) {
// block thread
}
// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);
// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
// do something with result
});