想法。逐行读取多个文件,连接它们,处理所有文件中的行列表。
实施。此can可通过以下方式实施:
import qualified Data.ByteString.Char8 as B
readFiles :: [FilePath] -> IO B.ByteString
readFiles = fmap B.concat . mapM B.readFile
...
main = do
files <- getArgs
allLines <- readFiles files
问题。这种情况无法忍受。值得注意的是,实际或用户时间比系统时间高几个数量级(使用UNIX time
测量),因此我认为问题在于在IO中花费太多时间。
我没有设法找到一种简单有效的方法来解决Haskell中的这个问题。
例如,处理两个文件(30.000行和每个1.2M)需要
20.98 real 18.52 user 0.25 sys
这是运行+RTS -s
时的输出:
157,972,000 bytes allocated in the heap
6,153,848 bytes copied during GC
5,716,824 bytes maximum residency (4 sample(s))
1,740,768 bytes maximum slop
10 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 295 colls, 0 par 0.01s 0.01s 0.0000s 0.0006s
Gen 1 4 colls, 0 par 0.00s 0.00s 0.0010s 0.0019s
INIT time 0.00s ( 0.01s elapsed)
MUT time 16.09s ( 16.38s elapsed)
GC time 0.01s ( 0.02s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 16.11s ( 16.41s elapsed)
%GC time 0.1% (0.1% elapsed)
Alloc rate 9,815,312 bytes per MUT second
Productivity 99.9% of total user, 98.1% of total elapsed
16.41 real 16.10 user 0.12 sys
为什么使用上面代码连接文件的速度太慢?
我应该如何在Haskell中编写readFiles
函数以使其更快?
答案 0 :(得分:3)
您应该准确地向我们展示您的处理步骤。
即使在您使用的多种输入文件(1.2 MB,每行30k行)上运行,该程序也非常高效:
import Control.Monad
import Data.List
import System.Environment
import qualified Data.ByteString.Char8 as B
readFiles :: [FilePath] -> IO B.ByteString
readFiles = fmap B.concat . mapM B.readFile
main = do
files <- getArgs
allLines <- readFiles files
print $ foldl' (\s _ -> s+1) 0 (B.words allLines)
以下是我创建输入文件的方法:
import Control.Monad
main = do
forM_ [1..30000] $ \i -> do
putStrLn $ unwords ["line", show i, "this is a test of the emergency"]
运行时间:
time ./program input -- 27 milliseconds
time ./program input input -- 49 milliseconds
time ./program input input input -- 69 milliseconds