Question

J'ai une fonction monadique getRate:

getRate :: String -> IO Double

Je voudrais mapper cette fonction sur une liste de chaînes de. Normalement, je voudrais juste faire:

mapM getRate ["foo", "bar"]

mais étant donné que chaque appel à getRate fait des appels du réseau, je voudrais paralléliser la carte de telle sorte que chaque débit est tiré par les cheveux dans un thread séparé (ou au moins répartis entre les files d'attente). Je pense à quelque chose comme

parMapM getRate ["foo", "bar"]

mais il n'y a pas de fonction de parMapM et parMap ne fonctionne pas avec les fonctions monadiques.

Que puis-je faire?

Était-ce utile?

La solution

Vous devez utiliser Control.Concurrent et synchroniser autour d'un Control.Concurrent.MVar; quelque chose comme:

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

Certaines parties de ce (fourchette, joindre) Rechercher séquentielle. Ce qui se passe dans la pratique est les fils sont tirés de façon séquentielle dans la fourchette et rendez-vous des promenades dans l'attente pour chaque fil à son tour. Mais l'IO arrive en même temps.

Notez que si vous avez besoin d'appeler des fonctions étrangères, vous devez utiliser forkOS au lieu de forkIO.

Autres conseils

Il y a aussi un paquet monade parallèle qui fournit mapM :: MonadParallel m => (a -> mb) -> [a] -> m [b] . En regardant l'instance IO pour MonadParallel il le fait de la même manière que dans la réponse de Dominic.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top