рд╣реЗрд▓реЛ, рд╣реИрдмрд░ред
рджреВрд╕рд░реЗ рджрд┐рди Siemarglрд╣рд╛рд╕реНрдХреЗрд▓ рдХреА рдорджрдж рд╕реЗ рдпреВрдирд┐рдХреНрд╕ рдкрд░ рдЬреАрдд рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рдЬрд┐рдЬреНрдЮрд╛рд╕реБ рд▓реЗрдЦ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдЖрдордВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ wcред рдмреЗрд╢рдХ, рдореИрдВ рдЗрд╕рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛, рдФрд░ рдХрдИ рдХрд╛рд░рдгреЛрдВ рд╕реЗ:
- рд▓реЗрдЦрдХ рдиреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рдорддрд▓рдм рдХреЗ рдПрдХрд▓-рдереНрд░реЗрдбреЗрдб рд╕рдВрд╕реНрдХрд░рдг рд╕реЗ рдирд┐рдЪреЛрдбрд╝ рд▓рд┐рдпрд╛, рдФрд░ рдПрдХрд▓-рдереНрд░реЗрдбреЗрдб рд╕рдВрд╕реНрдХрд░рдг рдмрд╣реБрдд рдзреАрдорд╛ рдерд╛
wc, - рдЙрд╕ рд▓реЗрдЦ рдореЗрдВ, рдЬреАрддрдиреЗ рдХреЗ рд▓рд┐рдП рдорд▓реНрдЯреАрдереНрд░реЗрдбрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдерд╛ (рдЬреЛ рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рд╕рд╛рдорд╛рдиреНрдп рдЬреНрдЮрд╛рди рдХреЗ рдмрдЬрд╛рдп рдзреЛрдЦрд╛ рджреЗрдиреЗ рдФрд░ рдЬреАрдд рдХреА рдереЛрдбрд╝реА рд╕реА рдмрд╛рдд рд╣реИ
wc) - рдЗрд╕рдХреЗ рд▓рд┐рдП, рд▓реЗрдЦрдХ рдХреЛ рддрд▓реНрд▓реАрди рд╣реЛрдирд╛ рдкрдбрд╝рд╛
trichoрдореЛрдирдбреНрд╕ рдФрд░ рдореЛрдиреЙрдпрдбреНрд╕ - рдирд╣реАрдВ, рдпрд╣ рдореЛрдиреЛрдбрд▓ рд╕реЛрдЪ рдХреЗ рдЖрдХрд░реНрд╖рдг рдХрд╛ рдПрдХ рдЙрддреНрдХреГрд╖реНрдЯ рдЪрд┐рддреНрд░рдг рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдИрдПрдордПрдЪрдУ рдЗрд╕ рддрд░рд╣ рдХреЗ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╣реИ, рдЦрд╛рд╕рдХрд░ рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕ рд╡рдЬрд╣ рд╕реЗ - рдХреЛрдб рдмрд╣реБрдд рдмрдбрд╝рд╛ рдирд┐рдХрд▓рд╛,
- рдФрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдЗрд╕рдХреЗ рд╕рд╛рде рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
wc, рдЬрд┐рд╕рдореЗрдВ рд╡рд┐рдХрд▓реНрдкреЛрдВ рдФрд░ рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХрд╛ рдПрдХ рд╕рдореВрд╣ рд╣реЛрддрд╛ рд╣реИ, рдпрд╣ рдПрд╣рд╕рд╛рд╕ рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдмрд╣реБрдд рд╣реА рдЦрд┐рд▓реМрдирд╛ рдПрдирд╛рд▓реЙрдЧ рд╣реИ, рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░ рдпрд╣ рдХрд┐рд╕реА рднреА рддрд░рд╣ рдЕрдЬреАрдм рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдереЛрдбрд╝рд╛ рдореВрд░реНрдЦрддрд╛рдкреВрд░реНрдг рд╣реИред
рдлрд┐рд░ рднреА, рдЕрдЬреАрдм рдЪреАрдЬреЗрдВ рдХрд░рдирд╛ рдПрдХ рдЕрдЪреНрдЫреА рдмрд╛рдд рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдЬ рд╣рдо рдКрдкрд░ рджрд┐рдП рдЧрдП рдкрд╣рд▓реЗ рдмрд┐рдВрджреБрдУрдВ рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдХреНрд░рд┐рд╕ (рдореВрд▓ рд▓реЗрдЦ рдХреЗ рд▓реЗрдЦрдХ рдХрд╛ рдирд╛рдо) рдХреЗ рдкрд░рд┐рдгрд╛рдо рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд░реЗрдВрдЧреЗред
рдлрд┐рд░, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдордиреЗ рдкрд┐рдЫрд▓реА рдмрд╛рд░ рдкрд╛рдпрд╛ рдерд╛, рдореИрдВ рд╕реА рдХреЛрдб рдирд╣реАрдВ рд▓рд┐рдЦ рд╕рдХрддрд╛, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЗрд╕реЗ рдпрд╛ рддреЛ рдирд╣реАрдВ рд▓рд┐рдЦрд╛, рдФрд░ рд╣рд╛рд╕реНрдХреЗрд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рддрд┐рдпреЛрдЧреА рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВ (рдХреНрд░рд┐рд╕ рдХреА рддрд░рд╣) wcрдЬреАрдПрдирдпреВ рдХреЛрд░реБрдЯрд┐рд▓реНрд╕ рд╕реЗ рдПрдХ рддрд╛рд▓рдореЗрд▓ рд░рдЦрддрд╛ рд╣реВрдВред рдЙрди рджреЛрд╕реНрддреЛрдВ рдХреЛ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдкрддрд╛ рд╣реИ рдХрд┐ рд╕реА рдореЗрдВ рдХреИрд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реИ, рдпрд╣ рдХреЛрдб рдПрдХ рджрд╢рдХ рдкреБрд░рд╛рдирд╛ рдирд╣реАрдВ рд╣реИ, рдФрд░ рдЙрдиреНрд╣реЛрдВрдиреЗ рдРрд╕реЗ рдЯреБрдХрдбрд╝реЛрдВ рдХреЛ рджреЗрдЦрддреЗ рд╣реБрдП рдкреНрд░рджрд░реНрд╢рди рдХрд╛ рдзреНрдпрд╛рди рд░рдЦрд╛:
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 , , ,
- 0.3 ,
- , , .
, ( ) , .
? 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 , . - , :
- LLVM- (
-fllvm) тАФ , . - (
-O2) тАФ -O , -O2 , ? - (
{-# INLINE wc #-}). , - , , , - . , , , .
, , , .
:
. -, . , -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рдереЛрдбрд╝рд╛ рдХрдо рдЦрд┐рд▓реМрдирд╛ рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рдП, рдФрд░ рдпрд╣ рднреА рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░реЗрдВ рдХрд┐ рдпрд╣ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдХреИрд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░реЗрдЧрд╛ред