【问题标题】:Is it safe to reuse a conduit?重复使用导管是否安全?
【发布时间】:2013-11-05 16:25:12
【问题描述】:

使用相同的管道值执行多个操作是否安全?类似的东西

do
  let sink = sinkSocket sock

  something $$ sink
  somethingElse $$ sink

我记得在导管的早期版本中,有一些肮脏的黑客行为使其不安全。目前情况如何?

(注意sinkSocket 不会关闭套接字。)

【问题讨论】:

    标签: haskell conduit


    【解决方案1】:

    这种用法是完全安全的。旧版本中的问题与模糊可恢复组件和不可恢复组件之间的界限有关。对于现代版本(我认为从 0.4 开始),两者之间的界限非常清晰。

    【讨论】:

      【解决方案2】:

      在“已使用”接收器的语义不会改变的意义上,重用接收器可能是安全的。但您应该注意另一个威胁:空间泄漏。

      这种情况类似于惰性列表:您可以在恒定空间中惰性地消耗一个巨大的列表,但如果您处理该列表两次,它将保存在内存中。递归单子表达式也可能发生同样的事情:如果你使用它一次它的大小是恒定的,但如果你重复使用它,计算的结构会保存在内存中,导致空间泄漏。

      这是一个例子:

      import Data.Conduit
      import Data.Conduit.List
      import Control.Monad.Trans.Class (lift)
      
      consumeN 0 _ = return ()
      consumeN n m = do
        await >>= (lift . m)
        consumeN (n-1) m
      
      main = do
        let sink = consumeN 1000000 (\i -> putStrLn ("Got one: " ++ show i))
        sourceList [1..9000000::Int] $$ sink
        sourceList [1..22000000::Int] $$ sink
      

      这个程序在我的机器上使用了大约 150M 的内存,但是如果你删除最后一行或者在两个地方重复 sink 的定义,你会得到一个很好的恒定空间使用。

      我同意这是一个人为的例子(这是我想到的第一个例子),大多数 Sinks 不太可能发生这种情况。例如,您的sinkSocket 不会发生这种情况。 (为什么这是人为的:因为接收器的 控制结构 不依赖于它获得的值。这也是它可能泄漏的原因。)但是,例如,对于源,这将是更常见。 (许多常见的源都表现出这种行为。sourceList 是一个明显的例子,因为它实际上会将源列表保存在内存中。但是,enumFromTo 没有什么不同,尽管没有数据要保存在内存中,只是一元计算的结构。)

      所以,总而言之,我认为意识到这一点很重要。

      【讨论】:

        猜你喜欢
        • 2013-08-01
        • 1970-01-01
        • 2016-02-13
        • 2013-08-11
        • 2012-10-28
        • 2014-09-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多