Hexoにとってスピードは常に重要です。3年前、Hexo 3.2はテンプレートのプリコンパイルにより生成速度を2倍に向上させました。そして現在はHexo 4.2となり、いくつかのパフォーマンス改善により、Hexo 3.2と比較して生成速度を30%向上させることに成功しました。
ベンチマーク
ベンチマークの設定方法をご紹介します。
- Travis CI - Ubuntu Xenial 16.04
- CPU:2コア
- RAM:7.5GB
- Hexoのデフォルトテーマ:landscape
- ランダムに生成された300件の記事。各記事には、一般的に使用されるMarkdown構文と、`highlight.js`をテストするためのコードブロックが含まれています。各記事のFront Matterには、固有のカテゴリと3つのタグも設定されています。
Hexo 3.2以降、レンダリングされたコンテンツは`warehouse` (`db.json`)にキャッシュされるため、コールド生成(`hexo g`の前に`hexo clean`を実行)とホット生成(`hexo clean`を実行しない)の両方のパフォーマンスをベンチマークでテストしました。各ベンチマークは`コールド => ホット => コールド`の順序で実行されます。メモリ使用量は`time`コマンドを使用して測定し、Resident Set Size(RSS)の値を取得します。
ベンチマークスクリプトはこちらにあります。
Node.js 8
Hexo 3.2 | Hexo 3.8 | Hexo 4.2 | ||||
---|---|---|---|---|---|---|
コールド処理 | 13.585秒 | 0% | 18.572秒 | +37% | 9.210秒 | -32% |
コールド生成 | 13.027秒 | 0% | 50.528秒 | +284% | 8.666秒 | -33% |
メモリ使用量(コールド) | 815.754MB | 0% | 1416.309MB | +69% | 605.312MB | -26% |
ホット処理 | 0.668秒 | 0% | 0.712秒 | +6% | 0.732秒 | +7% |
ホット生成 | 11.734秒 | 0% | 46.339秒 | +295% | 7.821秒 | -33% |
メモリ使用量(ホット) | 702.535MB | 0% | 1450.719MB | +106% | 821.512MB | +17% |
Node.js 10
Hexo 3.2 | Hexo 3.8 | Hexo 4.2 | ||||
---|---|---|---|---|---|---|
コールド処理 | 11.875秒 | 0% | 15.985秒 | +35% | 8.043秒 | -29% |
コールド生成 | 10.308秒 | 0% | 41.339秒 | +301% | 7.450秒 | -28% |
メモリ使用量(コールド) | 805.633MB | 0% | 1440.297MB | +79% | 599.008MB | -26% |
ホット処理 | 0.700秒 | 0% | 0.676秒 | -3% | 0.731秒 | +4% |
ホット生成 | 8.322秒 | 0% | 35.453秒 | +326% | 6.420秒 | -23% |
メモリ使用量(ホット) | 679.082MB | 0% | 1447.109MB | +113% | 789.527MB | +16% |
Node.js 12
Hexo 3.2 | Hexo 3.8 | Hexo 4.2 | ||||
---|---|---|---|---|---|---|
コールド処理 | 11.454秒 | 0% | 15.626秒 | +36% | 8.381秒 | -27% |
コールド生成 | 10.428秒 | 0% | 37.482秒 | +260% | 7.283秒 | -30% |
メモリ使用量(コールド) | 1101.586MB | 0% | 1413.359MB | +28% | 580.953MB | -47% |
ホット処理 | 0.724秒 | 0% | 0.790秒 | +9% | 0.790秒 | +9% |
ホット生成 | 8.994秒 | 0% | 35.116秒 | +293% | 6.385秒 | -29% |
メモリ使用量(ホット) | 696.500MB | 0% | 1538.719MB | +120% | 600.398MB | -14% |
Node.js 13
Hexo 3.2 | Hexo 3.8 | Hexo 4.2 | ||||
---|---|---|---|---|---|---|
コールド処理 | 11.496秒 | 0% | 14.970秒 | +29% | 8.489秒 | -26% |
コールド生成 | 10.088秒 | 0% | 36.867秒 | +265% | 7.212秒 | -28% |
メモリ使用量(コールド) | 1104.465MB | 0% | 1418.273MB | +28% | 596.233MB | -46% |
ホット処理 | 0.724秒 | 0% | 0.776秒 | +7% | 0.756秒 | +4% |
ホット生成 | 7.995秒 | 0% | 33.968秒 | +325% | 6.294秒 | -21% |
メモリ使用量(ホット) | 761.195MB | 0% | 1516.078MB | +99% | 812.234MB | +7% |
Hexoからのcheerio依存の削除
ベンチマーク結果からわかるように、Hexo 3.8では深刻なパフォーマンスの低下が見られました。#3129で導入された`meta_generator`フィルターが原因であることが判明しました。#3129では、`cheerio`を使用して`<head>`に`<meta name = "generator" content = "Hexo [version]">`を挿入するため、`cheerio`はHexoによって生成されたすべてのHTMLをメモリにロードしてDOMに解析する必要があります。
`cheerio`は高速ですが、数百のHTMLファイルをトラバースする際にはパフォーマンスのボトルネックが発生します。#3677で、`cheerio`をネイティブAPIに置き換える提案を行いました。#3671、#3680、#3685では、`open_graph()`ヘルパー、`meta_generator`フィルター、`external_link`フィルターの`cheerio`を正規表現に置き換え、hexo-util#137と#3850では、`cheerio`をより高速な`htmlparser2`に置き換えました。これで、Hexo 4.2では`cheerio`を完全に削除することができました。
レンダリング済みHTMLのキャッシュメカニズムの改善
レンダリング済みHTMLのキャッシュは、Hexo 3.0.0-rc4(`e8e45ed`)で導入されました。これは、レンダリング結果をキャッシュすることでHexoの生成パフォーマンスを向上させる試みでした。ただし、`hexo g`の実行中は各ルートが1回だけ使用されるため、パフォーマンスが向上しない一方でメモリが消費されます。#3756では、`hexo g`ではレンダリング済みHTMLのキャッシュが無効化され、`hexo s`では有効化されたため、`hexo g`のメモリ使用量が削減されました。
HexoからのLodash依存の削除
Lodashは、配列、数値、オブジェクト、文字列の操作を容易にする最新のJavaScriptユーティリティライブラリです。しかし、ES6に新しい機能が追加されるにつれて、Lodashの機能のほとんどはネイティブJavaScriptで置き換えられるようになりました。
Hexoは実際には1年前からLodashの依存関係を減らし始めており、#3285、#3290、warehouse#18などがあります。#3753では、You don’t (may not) need Lodash/Underscoreに従って、LodashをネイティブJavaScriptに徐々に置き換えることを提案しました。#3785、#3786、#3788、#3790、#3791、#3809、#3810、#3813、#3826、#3845、hexo-util#141、#3880、#3969を経て、LodashをHexoから正常に削除することができました。また、You don’t (may not) need Lodash/Underscoreに新しいPRを開き、`_.assignIn`の代替案をコミュニティに還元しました。
ユーティリティ関数の戻り値のキャッシュ
`hexo-util`には、相対パスを計算するための`relative_url(from, to)`、相対パスをURLに変換するための`url_for(path)`と`full_url_for(path)`、メールアドレスからgravatar URLを計算するための`gravatar(mail)`、指定されたURLが外部リンクかどうかを判断するための`isExternalLink(url)`など、多くのユーティリティがあります。これらの関数はHexoの生成プロセス中に数千回呼び出される可能性があり、同じパラメータが繰り返し渡される可能性があることがわかりました。そのため、パラメータのキーバリューと戻り値をキャッシュすることができます。このアイデアはhexo-util#162で実装されました。
今後の展望
#3776では、ユニットテストの一部としてCIにベンチマークを追加しました。それ以来、ベンチマークは(#3807や#3833のような)潜在的なパフォーマンスの低下を何度か発見するのに役立ち、#3129のような深刻なパフォーマンスの低下を回避するのに役立っています。そして、#4000では、ユニットケースにフレームグラフを追加するためにさらに一歩踏み出す予定です。これは、Hexoの生成プロセスをより最適化するのに役立ちます。Hexoにとって、スピードは常に重要です。