12

私は単項関数 getRate を持っています:

getRate :: String -> IO Double

この関数を文字列のリストにマップしたいと思います。通常は、次のようにします。

mapM getRate ["foo", "bar"]

しかし、getRate への呼び出しごとにネットワーク呼び出しが行われるため、マップを並列化し、各レートが個別のスレッドでフェッチされる (または少なくともキュー間で分散される) ようにしたいと考えています。みたいなことを考えている

parMapM getRate ["foo", "bar"]

ただし、parMapM 関数はなく、parMap はモナド関数では機能しません。

私に何ができる?

4

2 に答える 2

7

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

この部分(フォーク、結合)は順番に見えます。実際に起こっていることは、スレッドがフォークで順番に発射され、ランデブーが各スレッドを順番に待機することです。ただし、IOは同時に発生します。

外部関数を呼び出す必要がある場合は、forkIOの代わりにforkOSを使用する必要があることに注意してください

于 2010-02-10T00:23:18.633 に答える
6

mapM :: MonadParallel m => (a -> mb) -> [a] -> m [b]を提供する monad-parallel パッケージもあります。MonadParallel の IO インスタンスを見ると、ドミニクの回答と同じように行われます。

于 2010-06-24T13:25:04.327 に答える