Domanda

Ho una funzione getRate monadica:

getRate :: String -> IO Double

Mi piacerebbe mappare questa funzione nel corso di un elenco di stringa di. Normalmente, vorrei solo fare:

mapM getRate ["foo", "bar"]

ma dato che ogni chiamata a getRate rende le chiamate di rete, mi piacerebbe parallelizzare la mappa in modo che ciascuna aliquota viene recuperato in un thread separato (o almeno sparsi tra le code). Sto pensando a qualcosa di simile

parMapM getRate ["foo", "bar"]

, ma non v'è alcuna funzione parMapM e parMap non funziona con funzioni monadici.

Che cosa posso fare?

È stato utile?

Soluzione

Si dovrebbe usare Control.Concurrent e sincronizzare intorno ad un Control.Concurrent.MVar; qualcosa di simile:

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

Alcune parti di questo (forchetta, unire) Cerca sequenziale. Ciò che accade in pratica è i fili vengono sparati fuori sequenzialmente in forcella e appuntamento passeggiate attraverso attesa di ciascun filo a turno. Ma l'IO avviene contemporaneamente.

Si noti che se avete bisogno di chiamare funzioni stranieri si dovrebbe usare forkOS invece di forkIO.

Altri suggerimenti

C'è anche un pacchetto monade parallelo che fornisce MAPM :: MonadParallel m => (a -> mb) -> [a] -> m [b] . Guardando l'istanza IO per MonadParallel lo fa allo stesso modo come nella risposta di Dominic.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top