日々之迷歩

世の中わからんことだらけ

ITが複雑で難しくなっていく様に翻弄される日々です。微力ながら共著させていただいた「シェル・ワンライナー160本ノック」をよろしくお願い申し上げます。

カラム分割と文字列切り出し速度の処理系比較

シェル芸やると、空白区切りテキストファイルの扱いが多くなる。行ごとにカラムや文字列の切り出しというのはよくやる処理。

私がよく使う処理系毎で、速度はどんなもんだろうか?と思ったので比較してみた。厳密な比較になっていないので、あくまでも参考程度に。

パソコンスペック

処理系

  • OSX標準awk
  • GNU awk (HomeBrewでインストール)
  • Perl 5.18 (OSX標準添付)
  • Ruby 2.2.2 (rbenvでインストール)
  • Open usp Tukubaiのself (Python 2.7.9はHomeBrewでインストール)
  • Open uspTukubaiのself (Haskell版)

データ

NASAのWebサーバログ。昨日のシェル芸勉強会で使ったやつから、UTF-8やASCIIじゃないデータが入った行を掃除したもの。掃除の仕方やデータの大きさ等は下記の通り。

$ LANG=C grep '^[[:print:]]*$' access_log.nasa > access_log.nasa.ascii
$ ls -l access_log.nasa.ascii 
-rw-r--r--+ 1 papiro  staff  373054129  4 19 22:26 access_log.nasa.ascii
$ wc access_log.nasa.ascii 
 3461590 34613089 373054129 access_log.nasa.ascii

行数は約350万行弱程度。

処理内容

NASAのWebサーバログから、月と日付を切り出す。

$ head -n 5 access_log.nasa.ascii 
192.168.0.55 - - [01/Jul/1995:00:00:01 -0400] "GET /history/apollo/ HTTP/1.0" 200 6245
192.168.0.103 - - [01/Jul/1995:00:00:06 -0400] "GET /shuttle/countdown/ HTTP/1.0" 200 3985
192.168.0.21 - - [01/Jul/1995:00:00:09 -0400] "GET /shuttle/missions/sts-73/mission-sts-73.html HTTP/1.0" 200 4085
192.168.0.100 - - [01/Jul/1995:00:00:11 -0400] "GET /shuttle/countdown/liftoff.html HTTP/1.0" 304 0
192.168.0.21 - - [01/Jul/1995:00:00:11 -0400] "GET /shuttle/missions/sts-73/sts-73-patch-small.gif HTTP/1.0" 200 4179

空白区切りのデータと考えると、日付は4カラム目にある。月は5〜7文字目、日は2〜3文字目。下記のような感じで切り出す。

Jul 01
Jul 01
Jul 01
Jul 01
Jul 01

処理速度の結果

データファイルのキャッシュは効いた状態。LANG=Cをつけての比較。念のため2回繰り返し、大きな差が無いことを確認。

OSX標準awk
$ time LANG=C /usr/bin/awk '{print substr($4,5,3),substr($4,2,2)}' access_log.nasa.ascii > /dev/null
real  0m28.043s
user  0m27.302s
sys   0m0.277s
GNU awk
$ time LANG=C awk '{print substr($4,5,3),substr($4,2,2)}' access_log.nasa.ascii > /dev/null
real   0m3.967s
user   0m3.839s
sys    0m0.117s
Perl
$ time LANG=C perl -alne 'print substr($F[3],4,3), substr($F[3],1,2)' access_log.nasa.ascii > /dev/null
real   0m20.764s
user   0m20.585s
sys    0m0.139s
Ruby
$ time LANG=C ruby -alne 'print "#{$F[3][4..6]} #{$F[3][1..2]}"' access_log.nasa.ascii > /dev/null
real   0m10.970s
user   0m10.621s
sys    0m0.236s
Open usp Tukubai self (Python版)
$ time LANG=C /usr/local/bin/self 4.5.3 4.2.2 access_log.nasa.ascii > /dev/null
real   1m42.755s
user   1m41.014s
sys    0m0.865s
Open usp Tukubai self (Haskell版)
$ time LANG=C ~/bin/self 4.5.3 4.2.2 access_log.nasa.ascii > /dev/null
real   0m12.539s
user   0m12.181s
sys    0m0.301s
総評

最速はGNU awkだった。OSX標準のawkは、何者?なのかはわからん・・・MacユーザはHomebrewでGNU awk入れとこう。

$ /usr/bin/awk --version
awk version 20070501

$ /usr/local/bin/awk --version
GNU Awk 4.1.1, API: 1.1
Copyright (C) 1989, 1991-2014 Free Software Foundation.

Rubyが思ったより速い。今回の処理に限っては、Haskell版selfと同等の速度が出ている。Ruby-alneオプション使った自動毎行splitモードのワンライナーもありか?

しかし、カラム切り出しと文字列切り出しだけなら、selfコマンドは超ラクチンなんすよ奥さん・・・