我正在尝试通过交替的行将文件拆分为两个单独的文件。 (即写入文件1的行1,3,5,7 ..和写入文件2的行2,4,6,8 ...)。

我正在使用的文件约为700MB,因此当我看到内存使用量超过6GB时,我知道有问题。

main :: IO()
main = withFile splitFile ReadMode splitData
  where
    splitData h = do
      dataSet <- lines <$> hGetContents h
      let (s1,s2) = foldl' (\(l,r) x -> (x:r,l)) ([],[]) dataSet
      writeFile testFile $ unlines s1
      writeFile trainingFile $ unlines s2

我最初使用的是懒惰的foldl版本,但是经过一些研究,看来使用严格的版本会有所帮助。但是可惜的是,它并没有什么明显的不同。我也尝试使用-O2进行编译,但是也没有执行任何操作。

我正在使用GHC 7.10.2

我没有堆栈溢出,那么将所有内存用于什么呢?

最佳答案

正如@dfeuer在评论中所提到的,writeFile的使用将强制要写入的整个字符串都将被计算,这也将强制读取整个输入。造成空间泄漏的原因是,在写入第一个文件时,整个第二个文件必须保留在内存中,这很明显,一次只能将一个文件保留在一行中。实际上解决方案是逐行编写:

import Control.Monad
import System.IO

main :: IO ()
main =
  withFile splitFile ReadMode $ \hIn ->
  withFile testFile WriteMode $ \hOdd ->
  withFile trainingFile WriteMode $ \hEven ->
  zipWithM_ hPutStrLn (cycle [hOdd, hEven]) . lines =<< hGetContents hIn

该程序在恒定的空间中运行。

10-05 19:01