HTML5は、WebワーカーなどのAPIをサポートしており、Webページが安全な状況でマルチスレッドコードを実行できるようにします。ただし、Webワーカーは実際には多くの制限の対象となります。これは、メモリデータを真に共有できず、メッセージを使用して状態を通知できるため、真の意味で「マルチスレッド」と呼ぶことさえできないためです。
Webワーカーのインターフェイスは、使用するのが非常に不便です。基本的には、サンドボックスで独立したJSファイルを実行するサンドボックスが付属しており、ポストメスとオンメスゲを通してメインスレッドと通信します。
コードコピーは次のとおりです。
var Worker = new Worker( "my.js");
var bundle = {message: 'hello world'、id:1};
worker.postmessage(bundle); // PostMessageは、過去にシリアル化可能なオブジェクトを渡すことができます
worker.onmessage = function(evt){
console.log(evt.data); //メインスレッドのオブジェクトを持ってワーカーに渡されたオブジェクトを比較する
console.log(bundle); // {メッセージ: 'Hello World'、id:1}
}
コードコピーは次のとおりです。
// my.js
onmessage = function(evt){
var data = evt.data;
data.id ++;
ポストメサージ(データ); // {メッセージ: 'Hello World'、id:2}
}
結果は、スレッドで取得されたデータのIDが増加したことがわかりますが、それが渡された後、メインスレッドのバンドルのIDは変更されていません。したがって、スレッドで渡されるオブジェクトは実際にコピーされます。このようにして、スレッドはデータを共有せず、読み取りと書き込みの競合を回避するため、安全です。スレッドの安全性を確保するコストは、スレッド内のメインスレッドオブジェクトを操作する機能を制限することです。
このような限られたマルチスレッドメカニズムは、使用するのが不便です。もちろん、労働者がコードを同時に動作させるように見えるようにする能力をサポートできることを願っています。たとえば、次のように見えるサポートコード:
コードコピーは次のとおりです。
var Worker = new StreadWorker(bundle /*共有obj* /);
worker.run(function(bundle){
//ワーカースレッドでSTHをします...
this.runonuithread(function(bundle /*shared obj* /){
//メインUIスレッドでSTHを実行します...
});
// ...
});
このコードでは、ワーカーを起動した後、任意のコードをワーカーで実行させ、UIスレッド(DOMの読み取りや書き込みなど)を操作する必要がある場合、メインスレッドに戻ってthis.runonuithreadを実行できます。
では、このメカニズムを実装する方法は?次のコードを見てください。
コードコピーは次のとおりです。
function workerThread(sharedobj){
this._worker = new Worker( "thread.js");
this._completes = {};
this._task_id = 0;
this.sharedobj = sharedobj;
var self = this;
this._worker.onmessage = function(evt){
var ret = evt.data;
if(ret .__ ui_task __){
// UIタスクで実行します
var fn =(new function( "return"+ret .__ ui_task __))();
fn(ret.sharedobj);
}それ以外{
self.sharedobj = ret.sharedobj;
self._completes [ret.taskid](ret);
}
}
}
workerthread.prototype.run = function(task、complete){
var _task = {__thread_task __:task.tostring()、sharedobj:this.sharedobj、taskid:this._task_id};
this._completes [this._task_id ++] = complete;
this._worker.postmessage(_task);
}
上記のコードは、スレッドワーカーオブジェクトを定義します。このオブジェクトは、thread.jsを実行しているWebワーカーを作成し、共有オブジェクトSharedOBJを保存し、thread.jsによって送信されたメッセージを処理します。
ui_taskメッセージがthread.jsで送信された場合、このメッセージで渡された関数を実行します。それ以外の場合は、実行の完全なコールバックを実行して、thread.jsの書き込み方法を見てみましょう。
コードコピーは次のとおりです。
onmessage = function(evt){
var data = evt.data;
if(data && data .__ thread_task __){
var task = data .__ thread_task__;
試す{
var fn =(new function( "return"+task))();
var ctx = {
threadsignal:本当、
睡眠:function(interval){
ctx.threadsignal = false;
setimeout(_run、interval);
}、
runonuithread:function(task){
postmessage({__ ui_task __:task.tostring()、sharedobj:data.sharedobj});
}
}
function _run(){
ctx.threadsignal = true;
var ret = fn.call(ctx、data.sharedobj);
postmessage({error:null、returnValue:ret、__thread_task __:task、sharedobj:data.sharedobj、taskid:data.taskid});
}
_run(0);
} catch(ex){
postmessage({error:ex.tostring()、returnvalue:null、sharedobj:data.sharedobj});
}
}
}
thread.jsはUIスレッドからメッセージを受信していることがわかります。その中で最も重要なのはthread_taskです。これは、ワーカースレッドで実行する必要があるUIスレッドで渡される「タスク」です。関数はシリアル化できないため、文字列に渡されます。ワーカースレッドは、文字列を関数に解析して、メインスレッドで送信されたタスクを実行します(共有オブジェクトSharedOBJはタスクに渡されることに注意してください)。実行が完了すると、返された結果はメッセージを介してUIスレッドに渡されます。 Return Value ReturnValueに加えて、共有オブジェクトSharedOBJを詳しく見てみましょう。パスを渡すと、ワーカースレッドとUIスレッドがオブジェクトを共有していないため、割り当てを通じて両側のオブジェクトを人為的に同期します(このスレッドは安全ですか?なぜですか?)
プロセス全体が複雑ではないことがわかります。この実装の後、このスレッドワーカーは次の2つの用途を持つことができます。
コードコピーは次のとおりです。
var t1 = new WorkerThread({i:100} /*共有obj* /);
setInterval(function(){
t1.run(function(sharedobj){
sharedobj.i ++を返します。
}、
関数(r){
console.log( "t1>" + r.returnvalue + ":" + r.error);
}
);
}、500);
var t2 = new WorkerThread({i:50});
t2.run(function(sharedobj){
while(this.threadsignal){
sharedobj.i ++;
this.runonuithread(function(sharedobj){
w( "body ul")。appendchild( "<li>"+sharedobj.i+"</li>");
});
this.sleep(500);
}
sharedobj.iを返します。
}、function(r){
console.log( "t2>" + r.returnvalue + ":" + r.error);
});
この使用法により、コードは、フォーム用語とセマンティック用語の両方で優れた構造、柔軟性、保守性を提供します。
さて、それはすべて、Webワーカーの使用に関する議論のためです。興味のある学生は、このプロジェクトを見ることができます:https://github.com/akira-cn/workerthread.js(ワーカーはサーバーテストを使用する必要があるため、プロジェクトにCopycat httpd.jsを特別に配置します。これは非常にシンプルなHTTPサービスJSです。