I'm trying to use concurrency in Haskell for a specific optimization in which only one of two values is required, and depending on the situation, either one may be much faster to create than the other.
I thought I could just run 2 threads with forkIO, and then wait until a value is placed in an MVar. Here is a simple Test i have written for this:
import Control.Concurrent
main = do out <- newEmptyMVar
t1 <- forkIO (makeString out)
t2 <- forkIO (makeInt out)
v <- takeMVar out
killThread t1
killThread t2
case v of
Left s -> putStrLn s
Right i -> putStrLn $ show i
makeString out = do s <- return ( show (primes !! 10000))
putMVar out $ Left s
makeInt out = do i <- return 2
putMVar out $ Right i
primes = sieve [2..]
where sieve (x:xs) = x : (sieve $ filter ((/=0).(flip mod x)) xs)
Compiled with:
ghc --make -threaded Test
However, only the Left s case is ever reached, although getting the prime should take long enough for the makeInt thread to start (and return 2 really shouldn't take that much time). Why is that, and how do I fix this?
Concurrency means implementing a program by using multiple I/O-performing threads. While a concurrent Haskell program can run on a parallel machine, the primary goal of using concurrency is not to gain performance, but rather because that is the simplest and most direct way to write the program.
Concurrent Haskell extends Haskell 98 with explicit concurrency. Its two main underlying concepts are: A primitive type MVar α implementing a bounded/single-place asynchronous channel, which is either empty or holds a value of type α . The ability to spawn a concurrent thread via the forkIO primitive.
The problem here is laziness. The makeString
is just inserting a thunk to calculate show (primes !! 10000)
, which then gets evaluated by the main thread afterwards. Inserting the thunk is quite fast, so it happens to win the race in this case.
To force evaluation to happen within the thread, you can change return
to evaluate
:
makeString out = do s <- evaluate $ show (primes !! 10000)
putMVar out $ Left s
This should cause makeInt
to win the race in most cases (although it's not guaranteed).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With