2

我想为蒙特卡罗模拟处理几百个二进制数据块(“场景”)。每个场景由 100 万个浮点数组成。以下是我为场景数据创建虚拟二进制文件的方法:

import Data.Binary 
import qualified Data.ByteString.Lazy as B
import Data.Array.Unboxed

scenSize = 1000000
scens = 100

main = do
    let xs = array (1,scenSize) [(i, 0.0) | i <- [1..scenSize]] :: UArray Int Float
    let l = take scens $ Prelude.repeat xs
    B.writeFile "bintest.data" (encode l)
    return ()

这工作正常。现在我想处理场景。由于可能有很多场景(scens=1000 左右),因此应该一次懒惰地完成一个块的处理。我试过decodeFile了,但这似乎不起作用:

import Data.Binary 
import qualified Data.Array.IArray as IA
import Data.Array.Unboxed as A

main = do
    bs <- decodeFile "bintest.data" :: IO [UArray Int Float]
    mapM_ doStuff bs
    return ()

doStuff b = 
    Prelude.putStrLn $ show $ b IA.! 100000

这个程序似乎首先将所有数据加载到内存中,然后在运行结束时打印所有数字。它还在我的 32 位 Ubuntu 机器上使用大量内存和 scens=500 崩溃。

我究竟做错了什么?有没有一种简单的方法可以让程序懒惰地运行?

4

1 回答 1

4

decodeFile不偷懒,只看源码 -it calls decodeOrFail,它本身必须解析整个文件以确定成功或失败。

编辑:

所以我认为在原版binary中起作用的东西现在已经坏了(阅读:它现在是一个非懒惰的记忆猪)。我怀疑最漂亮的一种解决方案是使用惰性readFilerunGetIncremental然后手动将块推送到解码器中:

import Data.Binary
import Data.Binary.Get
import Data.ByteString.Lazy as L
import Data.ByteString as B
import qualified Data.Array.IArray as IA
import Data.Array.Unboxed as A

main = do
    bs <- getListLazy `fmap` L.readFile "bintest2.data"
    mapM_ doStuff bs
    return ()

doStuff b = print $ b IA.! 100000

重要的东西在这里:

getListLazy :: L.ByteString -> [UArray Int Float]
getListLazy lz = go decodeUArray (L.toChunks lz)
  where
    go :: Decoder (UArray Int Float) -> [B.ByteString] -> [UArray Int Float]
    go _ []       = []
    go dec (b:bs) =
      case pushChunk dec b of
        Done b' o a -> a : go decodeUArray (b' : bs)
        Partial f   -> case bs of
                          (x:xs) -> go (f $ Just x) xs
                          []     -> []
        Fail _ _ s -> error s -- alternatively use '[]'

    decodeUArray :: Decoder (UArray Int Float)
    decodeUArray = runGetIncremental get

请注意,此解决方案没有打扰解码然后通过解码器探测列表长度 - 我只是更改了您的生成器代码以输出大量数组而不是数组列表。

为了避免这样的代码,我认为管道将是要走的路。

于 2013-08-22T22:08:35.320 回答