【问题标题】:How can I use parMap with a monadic function?如何将 parMap 与一元函数一起使用?
【发布时间】:2011-01-15 01:30:13
【问题描述】:

我有一个单子函数 getRate:

getRate :: String -> IO Double

我想将此函数映射到字符串列表。通常,我会这样做:

mapM getRate ["foo", "bar"]

但由于每次调用 getRate 都会进行网络调用,我想并行化地图,以便在单独的线程中获取每个速率(或至少分散在队列中)。我正在考虑类似的事情

parMapM getRate ["foo", "bar"]

但没有 parMapM 函数,并且 parMap 不适用于单子函数。

我能做什么?

【问题讨论】:

    标签: multithreading haskell concurrency parallel-processing monads


    【解决方案1】:

    您应该使用 Control.Concurrent 并围绕 Control.Concurrent.MVar 进行同步;类似:

    fork1 :: (a -> IO b) -> a -> IO (MVar b)
    fork1 f x =
      do
        cell <- newEmptyMVar
        forkIO (do { result <- f x; putMVar cell result })
        return cell
    
    fork :: (a -> IO b) -> [a] -> IO [MVar b]
    fork f = mapM (fork1 f)
    
    join :: [MVar b] -> IO [b]
    join = mapM takeMVar
    
    forkJoin :: (a -> IO b) -> [a] -> IO [b]
    forkJoin f xs = (fork f xs) >>= join
    

    这部分(fork、join)看起来是连续的。在实践中发生的情况是线程在 fork 中按顺序触发,并且集合点依次遍历等待每个线程。但是 IO 是同时发生的。

    请注意,如果您需要调用外部函数,您应该使用forkOS 而不是 forkIO。

    【讨论】:

      【解决方案2】:

      还有一个提供mapM :: MonadParallel m => (a -> m b) -> [a] -> m [b] 的monad-parallel 包。查看 MonadParallel 的 IO 实例,它的执行方式与 Dominic 的回答相同。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-20
        • 2019-11-21
        • 2021-10-11
        • 2020-10-26
        • 1970-01-01
        相关资源
        最近更新 更多