1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BunAdvent Calendar 2023

Day 17

【Bun】readdir が Node.js より 40 倍高速ってホント?

Last updated at Posted at 2023-12-15

今日(2023/12/15)現在、Bunのバージョンは v1.0.18まで行ってますが(速いっ)、遅ればせながら2023/12/2 にリリースされた Bun v1.0.15 を眺めていたら、

「recursiveはfs.readdir()Node.js より 40 倍高速です」

と書いてあったので確かめてみました。

recursive (リカーシブ) は「再帰的」という意味なので、まぁそういう機能ですね。下のディレクトリまで順にみに行ってくれます。

Bunでは、v1.0.15 からですが、Node.js ではリファレンスによると v20.1.0, v18.17.0 と2つ書かれています。(Node.js の方は見ていなかったので詳細は判らないです。)

まずディレクトリをサーチするので、その前に mydir ディレクトリを作り、その下にdir1からdir100までのサブディレクトリを用意して、それをサーチする速度を比較することにします。

まず、mydir1/mydir2/ディレクトリを作りそこへ更にディレクトリを100個シェルで作ります。

ディレクトリを100個用意します
mkdir mydir1
cd mydir1
mkdir mydir2
cd mydir2

for i in {1..100}; do
  mkdir "dir$i"
done

mydir1 の下はこんな感じになります

できたディレクトリ
$ tree
.
└─ mydir1/
    └─ mydir2/
        ├─ dir1/
        ├─ dir2/
        ├─ dir3/
      省略
        └─ dir100/

では、コードをbun用とnode用で2つ作ります。普通は1つで良いのですが、今回は、ES Moduleモードを使ってなるべく同じ感じのコードで比較したいという事で、Node.jsでも ES Moduleが動く 拡張子 .mjs を使いました。 .mjs は bun でも動きます。(Bunは.js, .ts, .cjs, .mjs, .jsx, .tsxファイルを直接実行できます。あー楽ちん。)

まず、recursive設定の無い普通のコード。

recursive無し readdir-recursive-none.mjs
console.time('readdir')
import { readdir } from "fs/promises";
const results = await readdir('/home/tato/bun/readdir/mydir1');
console.log('count: ', results.length);
console.log(results); // ["a.js", "b/c.js" ...
console.timeEnd('readdir')

次に、{ recursive: true } 設定のあるコード。

'<ディレクトリへのパス>'の部分は、__dirnameがCommon JSでしかサポートされておらず、ES Moduleだと別途モジュール読み込まないといけないという事で手を抜きました。はい。bunならimport と __dirname まぜても使えるのになぁ。

recursive: true有り readdir-recursive-none.mjs
console.time('readdir')
import { readdir } from "fs/promises";
const results = await readdir('<ディレクトリへのパス>', { recursive: true });
console.log('count: ', results.length);
console.log(results); // ["a.js", "b/c.js" ...
console.timeEnd('readdir')

では結果を見てみましょう。まずは、Node.jsから。

Node.js で recursive-true 有りと無しを実行
$ node readdir-recursive-true.mjs #有り
[
  'mydir2',        'mydir2/...',   'mydir2/dir1',  'mydir2/dir10',
  'mydir2/dir100', 'mydir2/dir11', 'mydir2/dir12', 'mydir2/dir13',
  'mydir2/dir14',  'mydir2/dir15', 'mydir2/dir16', 'mydir2/dir17',
  'mydir2/dir18',  'mydir2/dir19', 'mydir2/dir2',  'mydir2/dir20',
  'mydir2/dir21',  'mydir2/dir22', 'mydir2/dir23', 'mydir2/dir24',
  'mydir2/dir25',  'mydir2/dir26', 'mydir2/dir27', 'mydir2/dir28',
  'mydir2/dir29',  'mydir2/dir3',  'mydir2/dir30', 'mydir2/dir31',
  'mydir2/dir32',  'mydir2/dir33', 'mydir2/dir34', 'mydir2/dir35',
  'mydir2/dir36',  'mydir2/dir37', 'mydir2/dir38', 'mydir2/dir39',
  'mydir2/dir4',   'mydir2/dir40', 'mydir2/dir41', 'mydir2/dir42',
  'mydir2/dir43',  'mydir2/dir44', 'mydir2/dir45', 'mydir2/dir46',
  'mydir2/dir47',  'mydir2/dir48', 'mydir2/dir49', 'mydir2/dir5',
  'mydir2/dir50',  'mydir2/dir51', 'mydir2/dir52', 'mydir2/dir53',
  'mydir2/dir54',  'mydir2/dir55', 'mydir2/dir56', 'mydir2/dir57',
  'mydir2/dir58',  'mydir2/dir59', 'mydir2/dir6',  'mydir2/dir60',
  'mydir2/dir61',  'mydir2/dir62', 'mydir2/dir63', 'mydir2/dir64',
  'mydir2/dir65',  'mydir2/dir66', 'mydir2/dir67', 'mydir2/dir68',
  'mydir2/dir69',  'mydir2/dir7',  'mydir2/dir70', 'mydir2/dir71',
  'mydir2/dir72',  'mydir2/dir73', 'mydir2/dir74', 'mydir2/dir75',
  'mydir2/dir76',  'mydir2/dir77', 'mydir2/dir78', 'mydir2/dir79',
  'mydir2/dir8',   'mydir2/dir80', 'mydir2/dir81', 'mydir2/dir82',
  'mydir2/dir83',  'mydir2/dir84', 'mydir2/dir85', 'mydir2/dir86',
  'mydir2/dir87',  'mydir2/dir88', 'mydir2/dir89', 'mydir2/dir9',
  'mydir2/dir90',  'mydir2/dir91', 'mydir2/dir92', 'mydir2/dir93',
  'mydir2/dir94',  'mydir2/dir95', 'mydir2/dir96', 'mydir2/dir97',
  ... 2 more items
]
readdir: 20.435ms

$ node readdir-recursive-none.mjs #無し
count:  1
[ 'mydir2' ]
readdir: 10.321ms

{ recursive: true }では簡単に再帰的に下のディレクトリまで拾っていますね。

次に、Bunでやってみます。

Node.js で recursive-true 有りと無しを実行
$ bun readdir-recursive-true.mjs #有り
[
  "mydir2", "mydir2/dir91", "mydir2/dir58", "mydir2/dir87", "mydir2/dir39", "mydir2/dir92", "mydir2/dir63",
  "mydir2/dir42", "mydir2/dir62", "mydir2/dir79", "mydir2/dir75", "mydir2/dir22", "mydir2/dir88",
  "mydir2/dir44", "mydir2/dir89", "mydir2/...", "mydir2/dir64", "mydir2/dir19", "mydir2/dir97",
  "mydir2/dir41", "mydir2/dir26", "mydir2/dir95", "mydir2/dir2", "mydir2/dir69", "mydir2/dir8",
  "mydir2/dir73", "mydir2/dir52", "mydir2/dir53", "mydir2/dir83", "mydir2/dir36", "mydir2/dir33",
  "mydir2/dir54", "mydir2/dir93", "mydir2/dir71", "mydir2/dir67", "mydir2/dir84", "mydir2/dir56",
  "mydir2/dir21", "mydir2/dir90", "mydir2/dir48", "mydir2/dir70", "mydir2/dir96", "mydir2/dir4",
  "mydir2/dir74", "mydir2/dir81", "mydir2/dir7", "mydir2/dir15", "mydir2/dir82", "mydir2/dir25",
  "mydir2/dir99", "mydir2/dir23", "mydir2/dir43", "mydir2/dir31", "mydir2/dir38", "mydir2/dir9",
  "mydir2/dir10", "mydir2/dir12", "mydir2/dir45", "mydir2/dir40", "mydir2/dir86", "mydir2/dir55",
  "mydir2/dir17", "mydir2/dir60", "mydir2/dir6", "mydir2/dir27", "mydir2/dir29", "mydir2/dir13",
  "mydir2/dir66", "mydir2/dir85", "mydir2/dir47", "mydir2/dir65", "mydir2/dir18", "mydir2/dir78",
  "mydir2/dir80", "mydir2/dir34", "mydir2/dir16", "mydir2/dir3", "mydir2/dir50", "mydir2/dir14",
  "mydir2/dir28", "mydir2/dir98", "mydir2/dir61", "mydir2/dir32", "mydir2/dir24", "mydir2/dir5",
  "mydir2/dir46", "mydir2/dir37", "mydir2/dir72", "mydir2/dir51", "mydir2/dir94", "mydir2/dir76",
  "mydir2/dir1", "mydir2/dir35", "mydir2/dir59", "mydir2/dir77", "mydir2/dir68", "mydir2/dir100",
  "mydir2/dir30", "mydir2/dir11", "mydir2/dir20", "mydir2/dir57", "mydir2/dir49"
]
[1.37ms] readdir

$ bun readdir-recursive-none.mjs #無し
count:  1
[ "mydir2" ]
[0.67ms] readdir

このベンチでは、Bunの方が40倍まではいかなかったけど、それでもやはり15倍くらい爆速でした。めでたし。

最近 Qiita に書いた Bun 関連の記事10選

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?