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