Waiting on two inputs in Haskell, simultaneously
The title may be a bit vague. This is what I mean:
Say I have two ways of getting input to my program. The first is via the keyboard, using the function ge开发者_如何学编程tLine
which blocks until a line is read. The other is, say, via a TChan
, where using readTChan chan
will also result in a block until a value is present in the channel, whereupon it will be read.
What I want to accomplish is being able to wait for both values, using a single thread and not allowing my CPU to jump to 100%. The moment one of the two values is available, it is fetched and the program resumes. (Say, using Either
to notify which of the two values was received.)
Is this possible?
Thank you very much!
I don't think "using a single thread" makes sense here. You must already be using multiple Haskell threads anyway to write to the TChan
. You should use two Haskell threads to do this, and use an MVar
or similar to communicate the first result to arrive. For example:
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)
A proper implementation would probably clean up the threads left lying around afterwards, btw.
I have two ways of getting input to my program
You should be able to use 2 threads, one per input source, which wait on their respective inputs, writing the result to a shared channel or mvar governed by a third thread.
There is the race :: IO a -> IO b -> IO (Either a b)
helper function in the "async" package on hackage.
Runs two IO actions concurrently, so one could be your getLine
and the other blocking on an MVar
or whatever. Returns an Either
indicating which one returned first (the other is canceled).
https://hackage.haskell.org/package/async-2.0.2/docs/Control-Concurrent-Async.html#v:race
精彩评论