ベンチマークをとろう TypeScript 編

何かしらの処理を書く際は考えうる複数の実装に対してベンチマークを取りましょう。 TypeScript でベンチマークスコアを計測する方法を紹介します。 Tech Lead のお仕事紹介第 3 弾
2020.04.15

ベンチマークを取ることは非常に重要です。「推測するな、計測せよ」という原則のとおり、複数の実装案が考えられる場合はベンチマークスコアを計測し、最も目的に叶うものを採用しましょう。

これは CX 事業本部の Tech Lead のお仕事紹介第 3 弾の記事です。

TypeScript でのベンチマークスコア計測

benchmark.js を用います。基本的な使い方についてはドキュメントを読んでいただくとして、ここでは TypeScript のサンプルを紹介します。

https://github.com/januswel/benchmark-divide-array-into-chunks

ポイントをいくつか紹介します。

npm スクリプト

誰でも簡単にベンチマークを実行できるようにするため、 npm スクリプトを定義しましょう。

{

  // snip

  "scripts": {
    "start": "npx ts-node ./index.ts"
  },

  // snip

}

ここでは index.tsts-node を用いて実行しています。

ベンチマークテストを TypeScript で書く

次がベンチマークテストの本体になります。

// ①
import * as Benchmark from 'benchmark'

// ②
import forVersion from './src/for'
import reduceVersion from './src/reduce'

// ③
const suite = new Benchmark.Suite

const src = Array.from({length: 1000})

// ④
suite.add('for version', () => {
  forVersion(src, 200)
}).add('reduce version', () => {
  reduceVersion(src, 200)
}).on('cycle', (event) => {
  console.log(String(event.target))
}).on('complete', function () {         // ⑤
  console.log(`Fastest is ${this.filter('fastest').map('name')}`)
})
.run({ async: true })

①で benchmark パッケージからもろもろを import していますが、 @types/benchmark のインストールが必要です。

②のようにベンチマークスコアを取りたい対象の関数は別途定義しておくと良いでしょう。本体がすっきりとします。

③で一連のベンチマークテストをまとめるためのスイートを生成し、④でどういった処理をテストしたいか、テスト完了後の処理などを指定します。⑤では Arrow Function ではなく function キーワードを使っていますが、 benchmark.js がベンチマーク結果を this としてこのコールバック関数を呼び出すからです。

テスト対象の関数

テスト対象の関数はいつもと変わらず定義しましょう。ここでは 2 種類の実装を思いついたので 2 つ書いています。

ベンチマーク結果

yarn start とうつとベンチマークテストが走ります。

$ yarn start
yarn run v1.22.4
$ npx ts-node ./index.ts
npx: 8個のパッケージを1.915秒でインストールしました。
for version x 1,267,795 ops/sec ±2.10% (77 runs sampled)
reduce version x 277,413 ops/sec ±0.76% (90 runs sampled)
Fastest is for version
✨  Done in 15.73s.

for version が 1 秒間に 1,267,795 回の実行が可能と出ています。それに対し、 reduce version は 1 秒あたり 277,413 回の実行が可能というスコアです。

まとめ

今回紹介したコードでは最も速い方法はどれか、という表示もされますが、大幅にスコアが異ならない限り、読みやすさやメンテナンスのしやすさなども考慮してアルゴリズムを選択しましょう。