我非常喜欢将管道/管道应用于流式IO源的概念。我感兴趣的是构建适用于非常大的日志文件的工具。从Python / Ruby迁移到Haskell的一个吸引人的地方是编写并行代码的简单方法,但我找不到任何这方面的文档。我怎样才能设置一个管道流,它从文件中读取行并对它们进行并行处理(即有8个核,它应该读取8行,并将它们移交给8个不同的线程进行处理,然后再次收集)等等,理想的是尽可能少的“仪式”......
可选地,可以注意是否需要按顺序重新连接线,如果这可能影响过程的速度?
我相信可以使用Parallel Haskell书中的想法自己拼凑一些东西,但在我看来,在Conduit工作流程中间并行(parmap等)运行纯函数应该非常简单?
答案 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
的每个值运行的操作以及Producer
个a
值。
它返回一个新的Producer
。在内部,生产者以a
批量读取groupsize
值,同时处理它们,并逐一产生结果。
代码使用Pipes.Group
将原始生成器“分区”为大小为groupsize
的子生成器,然后Control.Foldl
将每个子生成器“折叠”为一个列表。 / p>
对于更复杂的任务,您可以转向pipes-concurrency
或stm-conduit
提供的异步渠道。但是这些让你有点像香草管道/管道的“单一管道”世界观。