管道流动中的并行处理

时间:2014-11-04 18:23:51

标签: haskell conduit

我非常喜欢将管道/管道应用于流式IO源的概念。我感兴趣的是构建适用于非常大的日志文件的工具。从Python / Ruby迁移到Haskell的一个吸引人的地方是编写并行代码的简单方法,但我找不到任何这方面的文档。我怎样才能设置一个管道流,它从文件中读取行并对它们进行并行处理(即有8个核,它应该读取8行,并将它们移交给8个不同的线程进行处理,然后再次收集)等等,理想的是尽可能少的“仪式”......

可选地,可以注意是否需要按顺序重新连接线,如果这可能影响过程的速度?

我相信可以使用Parallel Haskell书中的想法自己拼凑一些东西,但在我看来,在Conduit工作流程中间并行(parmap等)运行纯函数应该非常简单?

1 个答案:

答案 0 :(得分:7)

作为PetrPudlák在他的评论中提到的“内部并行性”的一个例子,考虑这个函数(我使用pipes,但可以用conduit同样容易地实现):< / p>

import Control.Monad
import Control.Lens (view)
import Control.Concurrent.Async (mapConcurrently)
import Pipes
import qualified Pipes.Group as G
import qualified Control.Foldl as L

concProd :: Int -> (a -> IO b) -> Producer a IO r -> Producer b IO r
concProd groupsize action producer = 
      L.purely G.folds L.list (view (G.chunksOf groupsize) producer)
      >->
      forever (await >>= liftIO . mapConcurrently action >>= mapM G.yield) 

此函数将参数作为组大小,我们要为类型a的每个值运行的操作以及Producera值。

它返回一个新的Producer。在内部,生产者以a批量读取groupsize值,同时处理它们,并逐一产生结果。

代码使用Pipes.Group将原始生成器“分区”为大小为groupsize的子生成器,然后Control.Foldl将每个子生成器“折叠”为一个列表。 / p>

对于更复杂的任务,您可以转向pipes-concurrencystm-conduit提供的异步渠道。但是这些让你有点像香草管道/管道的“单一管道”世界观。