管道和非管道代码之间的并发考虑

gsp*_*spr 5 haskell api-design haskell-pipes

我正在为管道接口中的某些编码包装C库,但我已经做了一些需要做出的设计决策.

在设置C库之后,我们保持编码器上下文.有了这个,我们可以编码,或者改变一些参数(让我们将Haskell接口调用到最后一个函数tune :: Context -> Int -> IO ()).我的问题分为两部分:

  1. 编码部分很容易包装成一个Pipe Foo Bar IO (),但我也想曝光tune.由于编码上下文的同时使用必须受到锁定保护,因此我需要在管道中的每次迭代时锁定,并tune使用相同的锁进行保护.但现在我觉得我正在强迫用户隐藏锁定.我在这里吠叫错了吗?这种情况通常如何在管道生态系统中得到解决?在我的情况下,我希望我的特定代码所属的管道始终在其自己的线程中运行,同时进行调整,但我不想强迫任何用户使用这种观点.管道生态系统中的其他软件包似乎也不会强迫用户使用.
  2. 不再使用的编码上下文需要正确地去初始化.在管道生态系统中,如何确保IO在管道被破坏时处理这些事情(在这种情况下执行som 动作)?

一个具体的例子是包装压缩库,在这种情况下,上面可以是:

  1. 压缩强度是可调的.我们设置了管道并快速运行.假设必须序列化对压缩编解码器上下文的并发访问,那么最好如何在管道保持运行时允许更改压缩强度设置?
  2. 压缩库在设置时从Haskell堆中分配了一堆内存,当管道被拆除时,我们需要调用一些库函数来清理它.

谢谢......这可能都很明显,但我对管道生态系统还很陌生.

编辑:发帖后阅读,我很确定这是我在这里问过的最模糊的问题.啊! 对不起;-)

Gab*_*lez 4

关于(1),一般的解决方案是将您的Pipe类型更改为:

Pipe (Either (Context, Int) Foo) Bar IO ()
Run Code Online (Sandbox Code Playgroud)

换句话说,它接受Foo输入和tune请求,并在内部进行处理。

因此,我们假设您有两个对应Producer于输入和调整请求的并发:

producer1 :: Producer Foo IO ()

producer2 :: Producer (Context, Int) IO ()
Run Code Online (Sandbox Code Playgroud)

您可以使用它们pipes-concurrency来创建一个缓冲区,将它们都输入其中,如下所示:

example = do
    (output, input) <- spawn Unbounded
    -- input  :: Input  (Either (Context, Int) Foo)
    -- output :: Output (Either (Context, Int) Foo)

    let io1 = runEffect $ producer1 >-> Pipes.Prelude.map Right >-> toOutput output
        io2 = runEffect $ producer2 >-> Pipes.Prelude.map Left  >-> toOutput output
    as <- mapM async [io1, io2]
    runEffect (fromInput >-> yourPipe >-> someConsumer)
    mapM_ wait as
Run Code Online (Sandbox Code Playgroud)

您可以pipes-concurrency通过阅读本教程了解有关该库的更多信息。

通过强制所有调整请求通过相同的单线程,Pipe您可以确保不会意外地对该tune函数进行两次并发调用。

关于 (2),您可以通过两种方式使用 获取资源pipes。更复杂的方法是使用该pipes-safe库,它提供了一个bracket可以在 中使用的函数Pipe,但这对于您的目的来说可能有点过分,并且仅用于在管道的生命周期内获取和释放多个资源。一个更简单的解决方案是使用以下with习惯用法来获取管道:

withEncoder :: (Pipe Foo Bar IO () -> IO r) -> IO r
withEncoder k = bracket acquire release $ \resource -> do
    k (createPipeFromResource resource)
Run Code Online (Sandbox Code Playgroud)

然后用户只需写:

withEncoder $ \yourPipe -> do
    runEffect (someProducer >-> yourPipe >-> someConsumer)
Run Code Online (Sandbox Code Playgroud)

您可以选择使用该managed包,这会稍微简化类型并使获取多个资源变得更加容易。您可以通过阅读我的这篇博文来了解更多信息。