Haskellでwc -lを作った

String,ByteString,Textの速度比較を行うために、wc -lを作ってみました。
用意したコードは下記の通りです。


mywc_text.hs

{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative ((<$>))
import qualified Data.Text.Lazy as LazyT
import qualified Data.Text.Lazy.IO as LazyTI
import System.Environment (getArgs)
import qualified System.IO as SI

main :: IO ()
main = do
    fp <- getArgs
    case fp of
        []  -> p LazyTI.getContents
        [f] -> SI.withFile f SI.ReadMode $ p . LazyTI.hGetContents
    where
    p i = print =<< LazyT.count "\n" <$> i


mywc_bytestring.hs

import Control.Applicative ((<$>))
import qualified Data.ByteString.Lazy.Char8 as LazyBS
import System.Environment (getArgs)
import qualified System.IO as SI

main :: IO ()
main = do
    fp <- getArgs
    case fp of
        []  -> p LazyBS.getContents
        [f] -> SI.withFile f SI.ReadMode $ p . LazyBS.hGetContents
    where
    p i = print =<< LazyBS.count '\n' <$> i


mywc_string.hs

import Control.Applicative ((<$>))
import System.Environment (getArgs)
import qualified System.IO as SI

main :: IO ()
main = do
    fp <- getArgs
    case fp of
        []  -> p SI.getContents
        [f] -> SI.withFile f SI.ReadMode $ p . SI.hGetContents
    where
    p i = print =<< length . lines <$> i


このmywc_text,mywc_bytestring,mywc_stringと、wcコマンドで行数カウントの速度を競ってもらいます。
※追記: ghc -O2でコンパイルしました。


対象データ: 10GiB / 218201000行のテキストファイル。前回同様.emacsを繋げて作成。
結果:

./mywc_text       ~/test.txt  98.07s user  2.93s system 86% cpu 1:57.16 total
./mywc_bytestring ~/test.txt  9.61s user   2.66s system 13% cpu 1:30.26 total
./mywc_string     ~/test.txt  324.95s user 4.52s system 97% cpu 5:37.19 total
wc -l             ~/test.txt  2.96s user   2.72s system  6% cpu 1:27.51 total

おまけ

wc.pl

#!/usr/bin/perl

use strict;
use warnings;
use utf8;

my $lines = 0;
my $buffer;
open(FILE, $ARGV[0]) or die "dieeeeee.$!";
while (sysread FILE, $buffer, 4096) {
    $lines += ($buffer =~ tr/\n//);
}
print $lines, "\n";

同じ試験用データ(10GiB / 218201000行のテキストファイル)をこのPerlスクリプトに食わせます。

./wc.pl ~/test.txt  9.17s user 3.31s system 12% cpu 1:36.35 total