awk のパフォーマンス

Perlの利点 - サンプルコードによるPerl入門 と同じようなことを awk でも行ってみました。

ただし、以下のような点で awk が不利なことが考えられます。

  • awk では純粋な配列はなく全て連想配列である。
  • 前項とも関係するが、push のようなものがないため、自前で実装する必要がある。

awk は Perl 以上に TIMTOWTDI なところがあるのですが、まず考えられるものが以下のようなものです。

# array_push_1.awk
BEGIN {
    FS = ",";
}

{
    for (i = 1; i <= NF; i++) {
        arr[++j] = $i;
    }
}

つまり、split() 関数ではなく awk の FS を用いた自動分割を行う方法です。

# array_push_2.awk
{
    num = split($0, arr, ",");

    for (i = 1; i <= num; i++) {
        arr[++j] = arr[i];
    }
}

続いてのものは split() するものです。

最後に何となく近い記述のものを用意しました。

# array_push_3.awk
BEGIN {
    file = ARGV[1];

    while (getline < file > 0) {
        num = split($0, person, /,/);

        for (i = 1; i <= num; i++) {
            persons[++j] = person[i];
        }
    }
    close(file);
}

実際に実行してみましょう。 まずは Perl と Ruby から。

$ time perl array_push.pl test.log
perl array_push.pl test.log  3.21s user 0.29s system 97% cpu 3.592 total

$ time ruby array_push.rb test.log
ruby array_push.rb test.log  11.95s user 0.30s system 97% cpu 12.602 total

確かに Perl の方がパフォーマンスは良さそうです。

$ time gawk -f array_push_1.awk test.log
gawk -f array_push_1.awk test.log  5.73s user 0.47s system 98% cpu 6.324 total

$ time gawk -f array_push_2.awk test.log
gawk -f array_push_2.awk test.log  6.80s user 0.02s system 95% cpu 7.119 total

$ time gawk -f array_push_3.awk test.log
gawk -f array_push_3.awk test.log  8.95s user 0.54s system 98% cpu 9.641 total

我らが gawk ですが、良くもなく悪くもなくというパフォーマンスです。 では、ほぼ最速の LL と言われる mawk で実行してみます。

$ time mawk -f array_push_1.awk test.log
mawk -f array_push_1.awk test.log  2.04s user 0.21s system 94% cpu 2.383 total

$ time mawk -f array_push_2.awk test.log
mawk -f array_push_2.awk test.log  1.92s user 0.01s system 99% cpu 1.952 total

$ time mawk -f array_push_3.awk test.log
mawk -f array_push_3.awk test.log  2.21s user 0.23s system 98% cpu 2.466 total

単純なパフォーマンスであれば mawk がダントツですし、mawk に新しいメンテナーがアサインされて、さらにパフォーマンスの改善が行われていますので、awker としては mawk からも目が離せなくなりそうです。

tag_nawk.png tag_nawk.png tag_nawk.png tag_nawk.png