2010-01-11 8 views
8

Le titre peut être un peu vague. C'est ce que je veux dire:Attente de deux entrées dans Haskell, simultanément

Dites que j'ai deux façons d'obtenir des informations sur mon programme. Le premier est via le clavier, en utilisant la fonction getLine qui bloque jusqu'à ce qu'une ligne soit lue. L'autre est, disons, via un TChan, où l'utilisation readTChan chan entraînera également un bloc jusqu'à ce qu'une valeur soit présente dans le canal, après quoi il sera lu. Ce que je veux accomplir est d'être en mesure d'attendre les deux valeurs, en utilisant un seul thread et ne permettant pas à mon processeur de sauter à 100%. Au moment où l'une des deux valeurs est disponible, elle est récupérée et le programme reprend. (Dites, en utilisant Either pour indiquer laquelle des deux valeurs a été reçue.)

Est-ce possible?

Merci beaucoup!

+1

Que diriez-vous d'avoir un appel IO-fil getLine, et mettre le résultat dans le Tchan ainsi? Ça me semble que ça devrait marcher .. – yairchu

+0

Pourquoi exactement voulez-vous utiliser un seul fil? Que se passerait-il si, par exemple, vous n'attendriez pas trois entrées? Ou 5? Ou 10? Pourquoi les restrictions arbitraires? – ADEpt

+0

Je suppose que vous avez du code où plusieurs threads étaient utilisés et que vous aviez 100% CPU? Vous souhaiterez peut-être publier le code afin que les autres puissent voir pourquoi: la solution correcte est les threads et il peut s'agir simplement d'un problème d'implémentation. – Godeke

Répondre

12

Je ne pense pas que "l'utilisation d'un seul thread" ait un sens ici. Vous devez déjà utiliser plusieurs threads Haskell pour écrire sur le TChan. Vous devez utiliser deux threads Haskell pour cela, et utiliser un MVar ou similaire pour communiquer le premier résultat à arriver. Par exemple:

module Main where 

import System.IO 
import Control.Concurrent 
import Control.Concurrent.MVar 
import Control.Concurrent.STM 
import Control.Concurrent.STM.TChan 

main = do 
    chan <- newTChanIO 
    forkIO (threadTChanWrite chan) 
    threadMultiplexedRead chan 

threadTChanWrite chan = do 
    threadDelay 5000000 
    atomically $ writeTChan chan 3 

threadMultiplexedRead chan = do 
    mvar <- newEmptyMVar 
    forkIO (threadKeyboardRead mvar) 
    forkIO (threadTChanRead mvar chan) 
    v <- readMVar mvar 
    print v 

threadKeyboardRead mvar = do 
    str <- getLine 
    putMVar mvar (Right str) 

threadTChanRead mvar chan = do 
    v <- atomically (readTChan chan) 
    putMVar mvar (Left v) 

Une mise en œuvre correcte nettoiera probablement les fils laissés par la suite, par exemple.

5

J'ai deux façons d'obtenir les commentaires de mon programme

Vous devriez être en mesure d'utiliser 2 fils, une par source d'entrée, qui attendent leurs entrées respectives, écrit le résultat à un canal partagé ou Mvar gouverné par un troisième thread.

+0

-1: vous avez ignoré la façon dont Q demande un sol'n unique. –

+3

@Charles Vous manquez le point. Il est plutôt inutile de ne pas utiliser plus d'un thread, et le gars ne parvient même pas à dire pourquoi. – Rayne

+3

Il n'a pas besoin de dire pourquoi, et je ne vois pas comment nous savons que ce vœu est inutile. –

1

Il y a la fonction d'assistance race :: IO a -> IO b -> IO (Either a b) dans le paquet "async" sur le hackage.

Exécute deux actions d'E/S en même temps, donc l'une pourrait être votre getLine et l'autre bloquant sur un MVar ou autre. Renvoie un Either indiquant lequel est retourné en premier (l'autre est annulé).

https://hackage.haskell.org/package/async-2.0.2/docs/Control-Concurrent-Async.html#v:race

+1

IMO c'est la bonne réponse.La réponse acceptée est trop compliquée et cette réponse effectue le nettoyage que la réponse d'acceptation dit est nécessaire. Vous devez avoir une bonne raison d'utiliser 'forkIO' au lieu de' async'. –