anti scroll

ブラウザと小説の新しい関係を模索する

nehan(縦書き文庫の組版エンジン)をWebAssembly化することで、約3倍の高速化を達成しました

縦書き文庫組版エンジンであるnehan(js製)をRustで書き換え、WebAssemblyで実行したところ、約3倍の高速化に成功しました。

現時点ですでに運用されています。

感想としては「本当は10倍ぐらい速くなって欲しかったけど、そこまでは速度が出ずにトホホ…」という感じです。

3倍なら良いではないか、と思われる方もいるかもしれませんが、青空文庫の長編小説なんかは、だいたい40万字ぐらいあり、そのjsでの組版時間は(すごく遅い端末だと)27秒に達することもあります。

ちなみに手元のノートPC(メモリ8G)でjsに組版させると5秒ぐらいです。

この5秒が1.7秒ぐらいになるのは嬉しくても、27秒が9秒になっても、あんまり嬉しくないですよね。

だから、ずっと10倍を目標にしてきたのですが…

まあこれから頑張って、Rust側のソースを最適化していこうと思います。

ビューアーの変更点

  • 全ページの計算が3倍速くなった
  • 作品を開いたとき、自動で前回に開いたページまで移動するようになった
  • 全ページ計算してから表示されるようになった(以前は先頭ページが計算できたら、すぐに表示されていた)
  • 数式の表示やコードハイライトの機能は削除した

注意してほしいのは、全ページの計算が終わるまで、先頭ページが表示されない、という新しい仕様です。

(2022/09/10 追記:解決しました!)

作品の長さに関係なく、高速に作品が表示されるようになりました - anti scroll

これが問題になるのは、文字数のすごく多い作品(100万字以上とか)を、すごく遅い端末(古いスマホとか)で開いた場合です。

古い組版エンジンだと、たとえ遅い端末でも、とりあえず先頭ページ「だけ」は高速に表示されたため、そんなに「待たされた感」はなかったと思います。

しかし新しいビューアーだと、全ページの計算が終わらないと作品が表示されないので、遅い端末だと待たされ感が凄いことになりそうです。

なんでこんな作りになってしまったかというと、ウェブアプリ(js)と組版エンジン(wasm)の間で、非同期にデータをやり取りするのが難しいからです。

正確には、 js側のデータを非同期でwasmに送信することはできそうですが、wasm側のデータを非同期でjsに送信するのが難しいのです。

以前の組版エンジンであるnehan7(js製)では、全体の組版速度は遅くとも、先頭ページが組版できたら、さっさとアプリ側に表示させることができました。

どっちもjsなので、非同期なデータのやり取りがしやすかったのです。

読者が先頭ページを読んでいる間、裏でこっそり残りページを計算し続ける、みたいなこともできました。

しかしWebAssemblyだと「ちょっとずつ計算した結果を、ちょっとずつアプリ側(js)に渡す」みたいな非同期処理が難しいので、全ページ計算してjsに渡すしかありません。

今後の展望

とまあ、いくつか頭の痛い問題はありますが、しばらく新しいエンジンを運用してみます。

とりあえず、新し目のスマホやPCで開くぶんには、ほとんどのケースで快適になるのも事実ですので。

nehan8のコードは、いずれGithubに公開したいと思っていますが、時期はもうちょい先になりそうです。

というのも、仮にソースを公開したところで、中身でRustの実験的な機能を使っている関係上、普通のRustコンパイラではコンパイルできないからです(最新の開発者版コンパイラが必要)。

そのへんのことで無用な混乱を生むのも面倒なので、Rust側が安定してから公開することにします。

開発後記

nehanの大きなバージョンアップは今回で8回目になりますが、今回ばかりは本当に心が折れそうでした。

いつも組版エンジンの書き直しは地獄なのですが、今回は言語がRustに変わったので、なにもかもが新しいことだらけで、しんどかったです。

去年の8月から着手して、今年の7月末に完了ですから、まるまる1年かかった計算になります。

jsからTypeScriptにしたときですらしんどかったですが、今回はその比じゃありませんでした。

ただRustは良い言語だなと思いました。慣れるまでは大変でしたが。少なくともC++よりはずっと書きやすい言語だと思います。