рд╣реЗрд▓реЛ, рд╣реИрдмрд░ред
рджреВрд╕рд░реЗ рджрд┐рди 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
рдереЛрдбрд╝рд╛ рдХрдо рдЦрд┐рд▓реМрдирд╛ рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рдП, рдФрд░ рдпрд╣ рднреА рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░реЗрдВ рдХрд┐ рдпрд╣ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдХреИрд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░реЗрдЧрд╛ред