縦書き文庫の組版エンジンである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++よりはずっと書きやすい言語だと思います。