メインコンテンツまでスキップ

Golangのwasmを別スレッドで非同期に実行

· 約2分
maa123
maa123

Goのwasmでの実行が少し前に試したときにうまく行かなかった理由がメモリを1GBも確保して溢れている事がわかり(こちらの記事を偶然見つけ)、実行にはできたのですが、長時間かかる処理を行うとサイトが丸ごと固まってしまいました。

WebAssemblyは同一スレッドで動く事が原因と判明し、WebWorkerを使えば非同期に実行が可能でした

Golang側で非同期に処理を行っても(go func利用)同期実行されてしまうので複数スレッドで実行する場合はJavaScript側で複数のWebWorkerを動かす必要がありそうでした。

動かした時のコードを残しておきます

<script type="text/worker_javascript" id="worker_wasm">の中身

importScripts("https://cdn.jsdelivr.net/gh/golang/[email protected]/misc/wasm/wasm_exec.js");
const go = new Go();

//GO側からjs.Global().Call("wasm_progress", "文字列")で呼び出し
function wasm_progress(msg){
self.postMessage({'type': 'progress', 'val': msg});
}
self.addEventListener('message', e => {
switch (e.data.type) {
case 'init':
WebAssembly.instantiate(e.data.instance, go.importObject).then(res => {
go.run(res.instance).then(()=>{
self.postMessage({'type':'initend','val':0});
});
});
break;
case 'start':
//ここでgoで設定した関数をwasm_calc()とする
let result = wasm_calc(e.data.val);
self.postMessage({'type':'end','val':result});
break;
}
}, false);

main.js(inlineでも)

const createWorkerFromId = (sid) => {
return new Worker(URL.createObjectURL(new Blob([ document.getElementById(sid).textContent ], { type: "text/javascript" })));
}
(async () => {
let worker = createWorkerFromId('worker_wasm');
let res = await (await fetch("main.wasm")).arrayBuffer();
worker.postMessage({'type':'init', 'source': res});
worker.onmessage = (e) => {
switch (e.data.type) {
case 'initend':
//処理始める
break;
case 'progress':
//処理中
break;
case 'end':
//完了
break;
default:
console.warn('Err');
}
};
})();