代码之家  ›  专栏  ›  技术社区  ›  Bill

如何将parmap与一元函数一起使用?

  •  11
  • Bill  · 技术社区  · 15 年前

    我有一个单态函数getrate:

    getRate :: String -> IO Double
    

    我想把这个函数映射到一个字符串列表上。通常,我只需要:

    mapM getRate ["foo", "bar"]
    

    但是,由于对getRate的每个调用都进行网络调用,所以我希望将映射并行化,以便在单独的线程中获取每个速率(或者至少在队列之间分散)。我在想

    parMapM getRate ["foo", "bar"]
    

    但是没有parmapm函数,parmap不适用于一元函数。

    我能做什么?

    2 回复  |  直到 14 年前
        1
  •  6
  •   Dominic Cooney    15 年前

    应该在control.concurrent.mvar周围使用control.concurrent和synchronize;类似于:

    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中按顺序被触发,集合依次通过等待每个线程。但是IO同时发生。

    请注意,如果需要调用外部函数,则应使用 forkOS 而不是福基奥。

        2
  •  6
  •   Daniel    14 年前

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