рдЯреНрд╡реЗрдВрдЯреА рд╣рд╛рд╕реНрдХреЗрд▓ рд▓рд╛рдЗрдиреНрд╕ рд╕реЗ рдЬреАрддрдирд╛: рдЖрдкрдХрд╛ Wc рд▓рд┐рдЦрдирд╛

рд╣реЗрд▓реЛ, рд╣реИрдмрд░ред


рджреВрд╕рд░реЗ рджрд┐рди Siemarglрд╣рд╛рд╕реНрдХреЗрд▓ рдХреА рдорджрдж рд╕реЗ рдпреВрдирд┐рдХреНрд╕ рдкрд░ рдЬреАрдд рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рдЬрд┐рдЬреНрдЮрд╛рд╕реБ рд▓реЗрдЦ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдЖрдордВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ wcред рдмреЗрд╢рдХ, рдореИрдВ рдЗрд╕рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛, рдФрд░ рдХрдИ рдХрд╛рд░рдгреЛрдВ рд╕реЗ:


  • рд▓реЗрдЦрдХ рдиреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рдорддрд▓рдм рдХреЗ рдПрдХрд▓-рдереНрд░реЗрдбреЗрдб рд╕рдВрд╕реНрдХрд░рдг рд╕реЗ рдирд┐рдЪреЛрдбрд╝ рд▓рд┐рдпрд╛, рдФрд░ рдПрдХрд▓-рдереНрд░реЗрдбреЗрдб рд╕рдВрд╕реНрдХрд░рдг рдмрд╣реБрдд рдзреАрдорд╛ рдерд╛ wc,
  • рдЙрд╕ рд▓реЗрдЦ рдореЗрдВ, рдЬреАрддрдиреЗ рдХреЗ рд▓рд┐рдП рдорд▓реНрдЯреАрдереНрд░реЗрдбрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдерд╛ (рдЬреЛ рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рд╕рд╛рдорд╛рдиреНрдп рдЬреНрдЮрд╛рди рдХреЗ рдмрдЬрд╛рдп рдзреЛрдЦрд╛ рджреЗрдиреЗ рдФрд░ рдЬреАрдд рдХреА рдереЛрдбрд╝реА рд╕реА рдмрд╛рдд рд╣реИ wc)
  • рдЗрд╕рдХреЗ рд▓рд┐рдП, рд▓реЗрдЦрдХ рдХреЛ рддрд▓реНрд▓реАрди рд╣реЛрдирд╛ рдкрдбрд╝рд╛ trichoрдореЛрдирдбреНрд╕ рдФрд░ рдореЛрдиреЙрдпрдбреНрд╕ - рдирд╣реАрдВ, рдпрд╣ рдореЛрдиреЛрдбрд▓ рд╕реЛрдЪ рдХреЗ рдЖрдХрд░реНрд╖рдг рдХрд╛ рдПрдХ рдЙрддреНрдХреГрд╖реНрдЯ рдЪрд┐рддреНрд░рдг рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдИрдПрдордПрдЪрдУ рдЗрд╕ рддрд░рд╣ рдХреЗ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╣реИ, рдЦрд╛рд╕рдХрд░ рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕ рд╡рдЬрд╣ рд╕реЗ
  • рдХреЛрдб рдмрд╣реБрдд рдмрдбрд╝рд╛ рдирд┐рдХрд▓рд╛,
  • рдФрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдЗрд╕рдХреЗ рд╕рд╛рде рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП wc, рдЬрд┐рд╕рдореЗрдВ рд╡рд┐рдХрд▓реНрдкреЛрдВ рдФрд░ рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХрд╛ рдПрдХ рд╕рдореВрд╣ рд╣реЛрддрд╛ рд╣реИ, рдпрд╣ рдПрд╣рд╕рд╛рд╕ рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдмрд╣реБрдд рд╣реА рдЦрд┐рд▓реМрдирд╛ рдПрдирд╛рд▓реЙрдЧ рд╣реИ, рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░ рдпрд╣ рдХрд┐рд╕реА рднреА рддрд░рд╣ рдЕрдЬреАрдм рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдереЛрдбрд╝рд╛ рдореВрд░реНрдЦрддрд╛рдкреВрд░реНрдг рд╣реИред

рдлрд┐рд░ рднреА, рдЕрдЬреАрдм рдЪреАрдЬреЗрдВ рдХрд░рдирд╛ рдПрдХ рдЕрдЪреНрдЫреА рдмрд╛рдд рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдЬ рд╣рдо рдКрдкрд░ рджрд┐рдП рдЧрдП рдкрд╣рд▓реЗ рдмрд┐рдВрджреБрдУрдВ рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдХреНрд░рд┐рд╕ (рдореВрд▓ рд▓реЗрдЦ рдХреЗ рд▓реЗрдЦрдХ рдХрд╛ рдирд╛рдо) рдХреЗ рдкрд░рд┐рдгрд╛рдо рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд░реЗрдВрдЧреЗред


рдлрд┐рд░, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдордиреЗ рдкрд┐рдЫрд▓реА рдмрд╛рд░ рдкрд╛рдпрд╛ рдерд╛, рдореИрдВ рд╕реА рдХреЛрдб рдирд╣реАрдВ рд▓рд┐рдЦ рд╕рдХрддрд╛, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЗрд╕реЗ рдпрд╛ рддреЛ рдирд╣реАрдВ рд▓рд┐рдЦрд╛, рдФрд░ рд╣рд╛рд╕реНрдХреЗрд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рддрд┐рдпреЛрдЧреА рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВ (рдХреНрд░рд┐рд╕ рдХреА рддрд░рд╣) wcрдЬреАрдПрдирдпреВ рдХреЛрд░реБрдЯрд┐рд▓реНрд╕ рд╕реЗ рдПрдХ рддрд╛рд▓рдореЗрд▓ рд░рдЦрддрд╛ рд╣реВрдВред рдЙрди рджреЛрд╕реНрддреЛрдВ рдХреЛ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдкрддрд╛ рд╣реИ рдХрд┐ рд╕реА рдореЗрдВ рдХреИрд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реИ, рдпрд╣ рдХреЛрдб рдПрдХ рджрд╢рдХ рдкреБрд░рд╛рдирд╛ рдирд╣реАрдВ рд╣реИ, рдФрд░ рдЙрдиреНрд╣реЛрдВрдиреЗ рдРрд╕реЗ рдЯреБрдХрдбрд╝реЛрдВ рдХреЛ рджреЗрдЦрддреЗ рд╣реБрдП рдкреНрд░рджрд░реНрд╢рди рдХрд╛ рдзреНрдпрд╛рди рд░рдЦрд╛:


/* If the average line length in the block is >= 15, then use
   memchr for the next block, where system specific optimizations
   may outweigh function call overhead.
   FIXME: This line length was determined in 2015, on both
   x86_64 and ppc64, but it's worth re-evaluating in future with
   newer compilers, CPUs, or memchr() implementations etc.  */

Spoiler: рд╣рдо wcрдХрд┐рд╕реА рднреА рд╕рдорд╕реНрдпрд╛ рдХреЗ рдмрд┐рдирд╛ рдкрд░рд┐рдорд╛рдг рдХреЗ рдПрдХ рдЖрджреЗрд╢ рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рдУрд╡рд░рдЯреЗрдХ рдХрд░реЗрдВрдЧреЗ , рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдореБрд╣рд╛рд╡рд░реЗрджрд╛рд░ рдХреЛрдб рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗ рдФрд░ рдореВрд▓ рдХреЛрдб рдХреЛ рдмрджрд▓рдиреЗ рдФрд░ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рдкрд░ рдЖрдзреЗ рдШрдВрдЯреЗ рд╕реЗ рднреА рдХрдо рдЦрд░реНрдЪ рдХрд░реЗрдВрдЧреЗред


рдкреНрд░рдпреЛрдЧ рдХреА рд╕реНрдерд┐рддрд┐


рддреЛ, рдкрд╣рд▓реЗ рд╣рдо рдкреНрд░рдпреЛрдЧрд╛рддреНрдордХ рд╕реЗрдЯрдЕрдк рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░рддреЗ рд╣реИрдВред


рдбреЗрдЯрд╛


рдореИрдВрдиреЗ рдЗрд╕ рдлрд╝рд╛рдЗрд▓ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд┐рдпрд╛ рдФрд░ рдЗрд╕реЗ рдореЗрд░реЗ рд╕рд╛рде рдЪрд┐рдкрдХрд╛ рджрд┐рдпрд╛, рдЗрд╕рд▓рд┐рдП рдХреБрд▓ рдЖрдХрд╛рд░ рд▓рдЧрднрдЧ 1.8 рдЧреАрдЧрд╛рдмрд╛рдЗрдЯ рд╣реИ:


% for i in `seq 1 10`; cat part.txt >> test.txt
% du -sh test.txt
1.8G    test.txt

, test.txt tmpfs-, , IO.



Gentoo Linux Core i7 4770 32 .


- ghc 8.8.2.


wc coreutils 8.31, gcc 9.2 -O2 -march=native:


% wc --version
wc (GNU coreutils) 8.31
Packaged by Gentoo (8.31-r1 (p0))

, -march=native тАФ C, - - , : x86_64-, wc coreutils ( SIMD-, ).


, -O3 -O2 тАФ , -O2.



, time. time , , ,


  1. 0.3 ,
  2. , , .

, ( ) , .



? wc!


Unicode ( ), C-, wc LANG=C LC_ALL=C wc /path/to/test.txt. ? 10.4 . .


, (ru_RU.UTF-8) wc (7.20 ), , , , C- тАФ , .


, ( ), 0.2 тАФ , IO-bound-.


Haskell


, ?


, cs bs ( , ):


import qualified Data.ByteString.Lazy.Char8 as BS
import Data.Char

wc :: BS.ByteString -> (Int, Int, Int)
wc s =
    let (bs, ws, ls, _) = BS.foldl' go (0, 0, 0, False) s
     in (bs, ws, ls)
  where
    go :: (Int, Int, Int, Bool) -> Char -> (Int, Int, Int, Bool)
    go (!bs, !ws, !ls, !wasSpace) c =
        let addLine | c == '\n' = 1
                    | otherwise = 0
            addWord | wasSpace = 0
                    | isSpace c = 1
                    | otherwise = 0
         in (bs + 1, ws + addWord, ls + addLine, isSpace c)

, , ( ).


, , 9 wc. : 31.2 , 306% wc. 9 , , .


, ( , ), , , , .


?



-, , тАФ . :


{-# LANGUAGE Strict #-}
{-# LANGUAGE RecordWildCards #-}

import qualified Data.ByteString.Lazy.Char8 as BS
import Data.Char

data State = State
  { bs :: Int
  , ws :: Int
  , ls :: Int
  , wasSpace :: Bool
  }

wc :: BS.ByteString -> (Int, Int, Int)
wc s = (bs, ws, ls)
  where
    State { .. } = BS.foldl' go (State 0 0 0 False) s

    go State { .. } c = State (bs + 1) (ws + addWord) (ls + addLine) (isSpace c)
      where
        addLine | c == '\n' = 1
                | otherwise = 0
        addWord | wasSpace = 0
                | isSpace c = 1
                | otherwise = 0

bang-, - {-# LANGUAGE Strict #-}. , ?


, , тАФ 4 ! 7.56 , 75% wc, ! ?


, : , , . -


data State = State
  { bs :: {-# UNPACK #-} !Int
  , ws :: {-# UNPACK #-} !Int
  , ls :: {-# UNPACK #-} !Int
  , wasSpace :: !Bool
  }

Int- . , nursery area, , , тАФ , .


CSE


, isSpace c , тАФ . , , go :


    go State { .. } c = State (bs + 1) (ws + addWord) (ls + addLine) isSp
      where
        isSp = isSpace c
        addLine | c == '\n' = 1
                | otherwise = 0
        addWord | wasSpace = 0
                | isSp = 1
                | otherwise = 0

? тАФ 2.93 , 28% wc.


? ghc , , ? тАФ isSpace ( ) , common subexpression elimination.



тАФ ( ). , wc , . - , :


  1. LLVM- ( -fllvm) тАФ , .
  2. ( -O2) тАФ -O , -O2 , ?
  3. ( {-# INLINE wc #-}). , - , , , - . , , , .

, , , .


:


LLVM-O2,% wc
2.9328
тЬУ3.9638
тЬУтЬУ2.6126
тЬУ2.5925
тЬУ2.2321
тЬУтЬУтЬУ2.0219
тЬУтЬУ2.0119
тЬУтЬУ2.0119

. -, . , -O2 , , LLVM- , ( ).


, . , C (19%!). , .


.



, State, .


, Bool , . , Int, 1 True, 0 тАФ False? , , !


data State = State
  { bs :: Int
  , ws :: Int
  , ls :: Int
  , wasSpace :: Int
  }

wc :: BS.ByteString -> (Int, Int, Int)
wc s = (bs, ws, ls)
  where
    State { .. } = BS.foldl' go (State 0 0 0 0) s

    go State { .. } c = State (bs + 1) (ws + addWord) (ls + addLine) isSp
      where
        isSp | isSpace c = 1
             | otherwise = 0
        addLine | c == '\n' = 1
                | otherwise = 0
        addWord | wasSpace == 1 = 0
                | isSp == 1 = 1
                | otherwise = 0

(, Bool), . , , addWord guard' ( if) :


        addWord = (1 - wasSpace) * isSp

.


? , , 1.91 , 18% wc. , .



, ?


ASCII, isSpace. , . , , , .


, Data.ByteString.Lazy Data.ByteString.Lazy.Char8, Char.


:


{-# LANGUAGE Strict #-}
{-# LANGUAGE RecordWildCards #-}

module Data.WordCount where

import qualified Data.ByteString.Lazy as BS

data State = State
  { bs :: Int
  , ws :: Int
  , ls :: Int
  , wasSpace :: Int
  }

wc :: BS.ByteString -> (Int, Int, Int)
wc s = (bs, ws, ls)
  where
    State { .. } = BS.foldl' go (State 0 0 0 0) s

    go State { .. } c = State (bs + 1) (ws + addWord) (ls + addLine) isSp
      where
        isSp | c == 32 || c - 9 <= 4 = 1
             | otherwise = 0
        addLine | c == 10 = 1
                | otherwise = 0
        addWord = (1 - wasSpace) * isSp
{-# INLINE wc #-}

, 1.45 , 14% wc.


, тАФ , , .



, , . , : wasSpace , , :


wc s = (bs, ws + 1 - wasSpace, ls)
  where
    State { .. } = BS.foldl' go (State 0 0 0 1) s
    ...

, .


:


0.35 , ? - - ?


, , wc. :


main :: IO ()
main = do
  [path] <- getArgs
  contents <- BS.readFile path
  print $ wc contents

readFile . mmap. bytestring-mmap, ByteString' mmap- , main


main :: IO ()
main = do
  [path] <- getArgs
  contents <- unsafeMMapFile path
  print $ wc contents

, unsafeMMapFile ByteString, wc, . , unsafeMMapFile, , mmap- , .


тАФ , 0.04-0.06 0.35 . , .


mmap , : , , . , : , .



?


, , Unix-, . , , ST .


, , : , wc, , ┬л ┬╗ wc , , . , .


рдареАрдХ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдкреАрдбрд╝рд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ, рд╣рдо рднрд╡рд┐рд╖реНрдп рдХреЗ рд▓рд┐рдП рдпреЛрдЬрдирд╛рдУрдВ рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░реЗрдВрдЧреЗ: рдЕрдЧрд▓реЗ рд▓реЗрдЦ рдореЗрдВ рд╣рдо рдХреБрдЫ рдЕрдзрд┐рдХ рджрд┐рд▓рдЪрд╕реНрдк рдЪреАрдЬреЛрдВ рд╕реЗ рдирд┐рдкрдЯреЗрдВрдЧреЗ, рдЬрд╣рд╛рдВ рд╣рд╛рд╕реНрдХреЗрд▓ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЪрдордХ рдЬрд╛рдПрдЧрд╛ред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рд╣рдо рдЖрдЬ рдЬреЛ рдХреБрдЫ рднреА рдХрд░рддреЗ рд╣реИрдВ рдЙрд╕реЗ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рджреЗрдЦреЗрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдЦрд┐рд▓реМрдиреЗ рдХреЛ haskell wcрдереЛрдбрд╝рд╛ рдХрдо рдЦрд┐рд▓реМрдирд╛ рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рдП, рдФрд░ рдпрд╣ рднреА рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░реЗрдВ рдХрд┐ рдпрд╣ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдХреИрд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░реЗрдЧрд╛ред


All Articles