水底

ScalaとかC#とかネットワークとか

散々既出で今更だけどmacOSデフォルトのgrepがめちゃ遅だった

(あまりに内容が雑なのでポエム扱いで)

そこそこデカいファイルを扱っていたら気になったのでメモ. 一時期 grepが10倍速くなった と話題になったりしてましたが自分のユースケースでは最大2,000倍程度の速度差がありました (記事の内容とは関係ない部分のようですが).

TL;DR;

速いし多機能なGNUgrep使おう

通常はmacOSデフォルトのBSDgrepを, Perl拡張などを使う時のみGNUgrepを使っています (全部GNU版でもいいかなと思うもOSデフォルトを弄ると色々壊れそうで怖かったので…). 普段は速度的に気にならなかったのですが, そこそこデカいファイル, とはいえ300MB程度ですがBSDgrep使ったら遅くてつらみを背負いました.

計測

対象はマルチバイト中心で約300MB (26,000行) のxmlファイルで行いました. 特にオプション等は使わずに (grep $pattern $file) 雑に計測しました (ignore-caseとか考慮すると結構変わるかも).

(real/user/sys) BSD grep 2.5.1 GNU grep 3.1
'芸術' 0m5.502s (0m4.959s, 0m0.142s) 0m0.007s (0m0.001s, 0m0.002s)
'芸術[^家]' 0m6.280s (0m5.292s, 0m0.152s) 0m0.003s (0m0.001s, 0m0.001s)
'国内.*芸術' 0m5.109s (0m4.891s, 0m0.103s) 0m0.003s (0m0.001s, 0m0.002s)

1つ目は単なる一致, 2つ目は雑な正規表現, 3つ目はbacktrackするであろう正規表現で試しました. どのパターンでも750〜2000倍程度とかなりの速度差が出ました. 今回は面倒なので条件や理由は探求しません. 詳しい人いたら教えてくだし

インストール

Homebrewでビャっと入れときましょう. デフォルトだと ggrep という名前のコマンドとしてインストールされますが, --with-default-names オプションを付けるとOSデフォルトの grep を隠すようになります.

brew tap homebrew/dupes
brew install homebrew/dupes/grep # --with-default-names

おまけ

パイプラインを使う (cat $file | grep $pattern) と一方的に遅くなると思っていたけどそうでもない模様. GNU版は50〜90倍程度遅くなったがBSD版は僅かに速いという結果に (何故)

(real/user/sys) BSD grep 2.5.1 GNU grep 3.1
'芸術' 0m4.962s (0m4.830s, 0m0.222s) 0m0.166s (0m0.011s, 0m0.206s)
'芸術[^家]' 0m4.982s (0m4.891s, 0m0.223s) 0m0.274s (0m0.011s, 0m0.214s)
'国内.*芸術' 0m5.054s (0m4.927s, 0m0.231s) 0m0.162s (0m0.010s, 0m0.205s)