縦書き文庫の組版エンジンであるnehan(js製)をRustで書き換え、WebAssemblyで実行したところ、約3倍の高速化に成功しました。
現時点ですでに運用されていますが、ページを再読み込みしないと反映されない人もいるかも
本当は10倍ぐらい速くなって欲しかったのですが、そこまでは速度が出ずに、トホホ…という感じです。
3倍なら良いではないか、と思われる方もいるかもしれませんが、青空文庫の長編小説なんかは、だいたい40万字ぐらいあり、その組版時間は(すごく遅い端末だと)27秒に達することもあります。
ちなみに手元のノートPC(メモリ8G)だと5秒ぐらいで、最近のPCだともっと速いでしょうが、古いスマホなんかだと27秒ぐらいかかってしまうこともあるんでしょう。
この27秒が3倍速で9秒になっても、あんまり嬉しくないですよね。
だから、ずっと10倍(遅い端末でも2.7秒)を目標にしてきたのですが…
まあこれから頑張って、Rust側のソースを最適化していこうと思います。
ビューアーの変更点
- 全ページの計算が3倍速くなった
- 作品を開いたとき、自動で前回に開いたページまで移動するようになった
- 全ページ計算してから表示されるようになった(以前は先頭ページが計算できたら、すぐに表示されていた)
- 数式の表示やコードハイライトの機能は削除した
注意してほしいのは、全ページの計算が終わるまで、先頭ページが表示されない、という新しい仕様です。
これが問題になるのは、文字数のすごく多い作品(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++よりはずっと書きやすい言語だと思います。