我需要使用自定義編碼函數(我有)序列化一大串值。我已經做到了這一點,它的工作原理,但我也想計算有多少值被序列化和寫入磁盤,同時仍然使用相對恆定的內存量(即它不應該保持整個輸入列表,因爲它獲得非常大大)。如果沒有保持計數,二元,穀物和大火建造者的所有工作的要求(使用等效的B.writeFile "foo" . runPut . mapM_ encodeValue
);但無論我試圖對這些庫進行什麼操作,看起來ByteString似乎都會一直保留在內存中,直到完成,而不是一有塊可用就開始寫入磁盤(即使使用火焰的toByteStringIO
-builder)。序列化和計數值列表
這是一個最小的例子證明什麼,我一直在努力做的事情:
import Data.Binary
import Data.Binary.Put
import Control.Monad(foldM)
import qualified Data.ByteString.Lazy as B
main :: IO()
main = do let ns = [1..10000000] :: [Int]
(count,b) = runPutM $ foldM (\ c n -> c `seq` (put n >> return (c+1))) (0 :: Int) ns
B.writeFile "testOut" b
print count
當編譯和運行+RTS -hy
,結果是字節字符串值占主導地位的幾乎爲三角形的圖形。
到目前爲止,我發現(我不是一個大風扇)唯一的辦法是做循環(直接或foldM
)在IO使用B.appendFile
,而不是把內或直接構建一個Builder值,這對我來說看起來不是很優雅。有沒有更好的辦法?
爲什麼8192與其他值相反?我在哪裏可以找到'run'函數的定義和類型,因爲我無法在iteratee中找到它? – ivanm
儘管我認爲你的解決方案演示了我用自己的解決方案所遇到的問題:似乎不可能構建「ByteString」並計算同時有多少個值;你在寫入磁盤時似乎必須這樣做。 – ivanm
哦,而且你所做的與我的原始版本不同的一個方面是:如果我理解你的代碼,你將返回並打印保存到磁盤的**字節數**,而不是數字**值**。因此,它是錯誤的:( – ivanm