首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RWST管道的空间泄漏

RWST管道的空间泄漏
EN

Stack Overflow用户
提问于 2014-08-13 07:53:17
回答 2查看 1.1K关注 0票数 11

对以下程序的内存分析表明,noleak函数在常量内存中运行,而泄漏函数以线性方式泄漏内存。dflemstr指出,这可能是由于RWST导致了无限的分配链。是这种情况吗?还有什么其他解决办法?我其实不需要作家的单曲。

环境:

GHC 7.8.3在ARCH 64位

Pipe.hs -o管-prof

代码语言:javascript
复制
import Control.Concurrent (threadDelay)
import Control.Monad (forever)

import Pipes
import Control.Monad.Trans.RWS.Strict

main = leak

effectLeak :: Effect (RWST () () () IO) ()
effectLeak =
  (forever $ do
      liftIO . threadDelay $ 10000 * 1
      yield "Space") >->
  (forever $ do
      text <- await
      yield $ text ++ (" leak" :: String)) >->
  (forever $ do
      text <- await
      liftIO . print $ text
  )

effectNoleak :: Effect IO ()
effectNoleak =
  (forever $ do
      lift . threadDelay $ 10000 * 1
      yield "Space") >->
  (forever $ do
      text <- await
      yield $ text ++ (" leak" :: String)) >->
  (forever $ do
      text <- await
      lift . print $ text
  )

leak = (\e -> runRWST e () ()) . runEffect $ effectLeak

noleak = runEffect $ effectNoleak
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-08-13 11:41:12

RWST似乎实际上是罪魁祸首:

代码语言:javascript
复制
instance (Monoid w, Monad m) => Monad (RWST r w s m) where
    return a = RWST $ \ _ s -> return (a, s, mempty)
    m >>= k  = RWST $ \ r s -> do
        (a, s', w)  <- runRWST m r s
        (b, s'',w') <- runRWST (k a) r s'
        return (b, s'', w `mappend` w') -- mappend
    fail msg = RWST $ \ _ _ -> fail msg

如您所见,作者使用普通的mappend。由于(,,)的参数不严格,w `mappend` w'构建了一系列的块,甚至对() is rather trivialMonoid实例进行了处理

代码语言:javascript
复制
instance Monoid () where
        -- Should it be strict?
        mempty        = ()
        _ `mappend` _ = ()
        mconcat _     = ()

为了解决这个问题,您需要在元组中为w `mappend` w'添加严格性:

代码语言:javascript
复制
        let wt = w `mappend` w'
        wt `seq` return (b, s'', wt) 

但是,如果您无论如何都不需要Writer,那么只需使用ReaderT r (StateT st m)

代码语言:javascript
复制
import Control.Monad.Trans.Reader
import Control.Monad.Trans.State.Strict

type RST r st m = ReaderT r (StateT st m)

runRST :: Monad m => RST r st m a -> r -> st -> m (a,st)
runRST rst r st = flip runStateT st . flip runReaderT r $ rst

但是,考虑到这将迫使您将计算转换为正确的monad,您可能需要使用lift来代替。代码将保持不变,但在本例中导入如下

代码语言:javascript
复制
import Control.Monad.Reader
import Control.Monad.State.Strict
票数 12
EN

Stack Overflow用户

发布于 2014-08-13 13:35:41

泽塔是对的,空间泄漏是因为WriterTWriterTRWST (都是“严格的”版本和懒惰的版本)总是泄漏空间,不管您使用的是哪种单类。

我为这个here编写了一个更长的解释,但这里有一个总结:避免泄漏空间的唯一方法是使用StateT monad模拟WriterT,其中tell使用严格的put进行模拟,如下所示:

代码语言:javascript
复制
newtype WriterT w m a = WriterT { unWriterT :: w -> m (a, w) }

instance (Monad m, Monoid w) => Monad (WriterT w m) where
    return a = WriterT $ \w -> return (a, w)
    m >>= f  = WriterT $ \w -> do
        (a, w') <- unWriterT m w
        unWriterT (f a) w'

runWriterT :: (Monoid w) => WriterT w m a -> m (a, w)
runWriterT m = unWriterT m mempty

tell :: (Monad m, Monoid w) => w -> WriterT w m ()
tell w = WriterT $ \w' ->
    let wt = w `mappend` w'
     in wt `seq` return ((), wt)

这基本上相当于:

代码语言:javascript
复制
type WriterT = StateT

runWriterT m = runStateT m mempty

tell w = do
    w' <- get
    put $! mappend w w'
票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25280852

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档