2016年11月2日水曜日

WebWorkerのpostMessageは非同期?

先日サンプルを作成して比較した結果、Workerスレッドの方がわずかに速いという結果になったのですが、数回分の試験データを比較した時に気になった点がありました。

タイトルの通り、postMessageは非同期なのか?ということが気になったので、それをプログラムで動作確認しました。




[ 仮説 ]
・本当はメインスレッドとWorkerスレッドの速度にはある程度の差がある。
・Workerスレッド側の情報はpostMessageを使わないとメインスレッドに送れないが、そのpostMessageが同期的(メインスレッド側のonmessageイベントの完了を待つ)だと、Workerスレッドの方が速かったとしてもメインスレッドに足を引っ張られてしまう。

[ 検証用プログラム ]
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>web worker</title>
</head>
<body></body>
<script type="text/jscript">
resizeTo(300,300)
function getFunctionBody(fun){
return fun.toString().trim().match(/^function[\s\w]*\([\w\s,]*\)\s*{([\w\W]*?)}$/)[1]
}
function fun2Worker(fun){
var str=getFunctionBody(fun), blob=new Blob([str], {type:'text/javascript'}), url=URL.createObjectURL(blob), worker
try{worker = new Worker(url)}
catch(e){
// Workerに渡すアドレスは同一生成元ポリシーを守らなければいけない。
// 変数urlの中身は「brob:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX」のランダムな文字列
// 呼び出し元ファイルのアドレスがローカルのものなら、ローカルPathしか渡せない。
var fs=new ActiveXObject('Scripting.FileSystemObject'), path=fs.getSpecialFolder(2)+'/'+fs.getTempName()+'.js', ws=fs.CreateTextFile(path)
ws.Write(str)
ws.Close()
worker = new Worker(path)
}
return worker
}
worker = fun2Worker(function(){
// ワーカー側スコープ
onmessage = function(e){
postMessage('work:'+(new Date()).getTime()+' start')
postMessage('work:'+(new Date()).getTime()+' end')
}
})
worker.onmessage = function(e){
f1(e.data+'\n')
var 開始=f0(), 期間=100, カウント=0
while((f0()-開始) < 期間){ (カウント++ % 100000) ? 0 : f1(カウント+' ') }
}
文字列 = ''
f0=function(){return (new Date()).getTime()}
f1=function(str){文字列 += str}
onload=function(){
f1('main:'+f0()+' start\n')
worker.postMessage(0)
f1('main:'+f0()+' end\n')
var 開始=f0(), 期間=1000, カウント=0
while((f0()-開始) < 期間){ カウント++ }
f1(' \n')
f1(開始+'\n')
f1(f0()+'\n')
f1(' '+'\n')
setTimeout(function(){document.body.innerText = 文字列}, 5000)
}
</script>
</html>


[ 仮説が正しい場合の実行結果(予想) ]
main:00000 start
work:00000 start
1 100001 200001 300001
work:00100 end
1 100001 200001 300001
main:00200 start
 
00200
01200
 


[ 実際の結果 ]




[ 結果についての考察 ]
メインスレッド側のpostMessageはworker側のonmessageの完了を待機していない(非同期)。
Workerスレッド側のonmessageはpostMessageを実行した呼出し元関数の完了を待機している(同期)。


[ 追加情報 ]
gistの方のRevisionsを見ていただければ分かるように、試験方法は試行錯誤しています。
Workerスレッド側のonmessageが同期的に見えるのはメインスレッド側が試験中にDOMエレメント操作しているせいかも?と思い文字列だけでまとめて全ての処理が終わってから一括で表示するように変更したりしています。


[ 検証環境 ]
Windows 7 Pro SP1 32bit
IE 11.0.9600.18499 更新ver 11.0.36(KB3191492)
mshta.exe ver 11.0.9600.16428


[ 異なる環境での実行結果 ]



[ 今後の予定 ]
今回は「同期なのか、非同期なのか」がメインテーマなので、それだけを確認しました。
先日から気になっている「スレッドごとの速度の違い」は今回の実験結果を踏まえて適切な評価方法を考えて試験します。

0 件のコメント:

コメントを投稿