rya*_*hza 9 performance haskell
如何在恒定空间中使用monadic动作折叠惰性列表?我试图解决的问题是聚合一个大文件,我相信为了性能我需要可变性.我有一个使用可变向量在ST工作的实现,但它使用了太多的内存.以下是我正在尝试的一个例子.我还对Conduit进行了简要的实验,但似乎没有提供任何改进.
ST forM_:
import Control.Monad (forM_)
import Control.Monad.ST.Trans as STT
import Control.Monad.Identity as Identity
testST :: Int
testST = do
Identity.runIdentity $ STT.runST $ do
a <- STT.newSTRef 0
forM_ [1..10000000] (\x -> do
a' <- STT.readSTRef a
STT.writeSTRef a (a' + x)
)
STT.readSTRef a
Run Code Online (Sandbox Code Playgroud)
导管:
import Data.Conduit (($=),(=$),($$))
import qualified Data.Conduit as C
import qualified Data.Conduit.List as CL
testCL :: IO Int
testCL = CL.sourceList [1..10000000] $$ CL.foldM (\a x -> return (a + x)) 0
Run Code Online (Sandbox Code Playgroud)
Dan*_*ner 15
问题不在于折叠,而在于折叠体.这个程序分配了很多:
testST = runST $ do
ref <- newSTRef 0
forM_ [1..10000000] $ \x -> do
val <- readSTRef ref
writeSTRef ref (val + x)
readSTRef ref
Run Code Online (Sandbox Code Playgroud)
这个程序,其唯一的区别是writeSTRef在线,几乎没有分配:
testST = runST $ do
ref <- newSTRef 0
forM_ [1..10000000] $ \x -> do
val <- readSTRef ref
writeSTRef ref $! val + x
readSTRef ref
Run Code Online (Sandbox Code Playgroud)
两段代码之间的区别是对正在发生的事情的一个很好的提示:在前者中,您正在创建对具有10000000层应用程序的深层嵌套thunk的引用+; 而后者在每一步都会使thunk变平.
顺便说一下,这个常见的陷阱在文档中明确地modifySTRef提到了.