LoginSignup
6
6

More than 5 years have passed since last update.

EmscriptenのスクリプトをWeb Workerで実行する

Posted at

この前のナンバーリンクソルバーについて改良を行なっていたのですが、さすがにSATソルバーをフロントエンドでそのまま回すのは負担が重いので、Web Workerで処理を行ってみることにしましたが、Emscripten特有の注意点が1つありました。

おことわり

なお、この記事はEmscriptenでコンパイルした後にWeb Workersで複数スレッド動作をさせることを前提としたC/C++コードを書く、という意味合いの記事ではありません。もともとあったC/C++のコードベースをEmscripten化したものについて、Web Workerで動作させる、という内容です。

Web Workerとは

JavaScriptは基本的にシングルスレッドのモデルをとっているので、一度には1つの処理しか進行しません。AjaxやsetTimeout、イベントなど非同期実行の処理は数多くありますが、これらとて1つの処理をこなしている間に別なことをすることはできません。

一方、Web Workerは、ブラウザのメイン動作とは別個のスレッドでJavaScriptを実行できる機能です。ここで複雑な処理を進めれば、途中で処理を切らなくても、ブラウザのUIを固まらせたりすることはありません。

制約事項

ただし、もともとシングルスレッドだったところに「後付け」のような形で導入されたこともあって、できること・できないことがはっきりしています。

できること

  • ブラウザと関係ない純粋JavaScriptとしての処理
  • XMLHTTPRequest、Web Socketなどを使った通信
  • setTimeoutsetIntervalといったタイマー系API
  • importScriptsによる別なスクリプトのロード
  • consoleを用いたデバッグ出力
  • postMessageによるメインスレッドとのデータのやり取り

できないこと

  • DOM操作
  • メインスレッドの変数操作

とりわけ、メインスレッドとデータをやり取りする手段はpostMessageだけです。

postMessageとは

postMessageは、ブラウザ内の異なるコンテキスト(クロスドメインなど)で安全にデータをやり取りするための仕組みです。Web Workerと本体スレッドの間でも、これを利用してデータをやり取りすることになります。

  • データの送信…postMessage()
  • データの受信…messageイベントとして来るので、onmessageとしてハンドラをセットする、もしくはaddEventListenerで待ち受ける

Emscriptenコードが…動かない

さて、そんな感じでWeb Workerを動かすのですが、最初からC/C++で書かれたプログラムやライブラリは、性質上DOMにアクセスすることもないので、Web Workerで動かすには最適です。

で、Worker内からimportScriptsでEmscriptenコードを呼び出して、実行しようとしたのですが、なんと「Moduleが見つかりません」とエラーになってしまいました。コードを読んでみると、windowのある通常のブラウザ環境では自動でwindow.Moduleを定義するのですが、Worker環境ではそうなっていなかったためにModuleが利用できない状態となっていました。対策として、事前にvar Module={};としてセットすべき変数を用意しておくことで、正常に呼べるようになりました。

このあたりについての実際のコードがありますので、ご参考になれば幸いです。

外部リンク

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6