Reputation: 2986
In Haskell, how can I run multiple (monad?) functions (such as print
) in parallel and see their output in the order of their finish time? I want three processes each one ending up in a print function.
import Control.Parallel
main = a `par` b `pseq` (a,b)
where
a = print("ack",ack 3 10)
b = print("fac",fac 42)
If I don't use pseq
, it will show the last one specified in par
combination. I want to make sure all processes are finished before the program ends. I tried this but it does not show the output of a,b:
...
main = a `par` b `pseq` print("done.")
...
Note: my program ends with the following lines:
fac 0 = 1
fac n = n * fac (n-1)
ack 0 n = n+1
ack m 0 = ack (m-1) 1
ack m n = ack (m-1) (ack m (n-1))
Upvotes: 0
Views: 440
Reputation: 1766
In the C family of languages, there's a difference between these 2 lines
a = foobar; // This just sets a to be a function pointer to foobar
b = foobar(); // This actually runs foobar and stores the result in `b`
Your code basically has the same problem as if you were writing C and forgot the ()
at the end of all your function calls. It assigns the function pointers a
and b
in parallel but doesn't actually call them.
If you are writing pure functions in Haskell, you can add parallelism using par
, but it doesn't work for IO
because IO a
is like a function pointer. Your code "evaluates" a
and b
in parallel but the result of that evaluation is still waiting for you to actually execute it.
For code that lives in IO
, you have to import Control.Concurrent
and use the function forkIO
to create the new thread. Then because the child threads all automatically die when the main thread finishes, you need some way of making the main thread wait (I'll use MVar
s in the example because they're the simplest reliable way to do it)
import Control.Concurrent
import Control.Concurrent.MVar
main = do
-- MVars have a type parameter because you can also use them to send data
-- between threads, but in this example I'm basically just using them as locks
await <- newEmptyMVar :: IO (MVar ())
bwait <- newEmptyMVar :: IO (MVar ())
forkIO $ print ("ack",ack 3 10) >> putMVar await ()
forkIO $ print ("fac",fac 42) >> putMVar bwait ()
takeMVar await
takeMVar bwait
Upvotes: 1
Reputation: 1521
Don't use Control.Parallel
for running IO actions concurrently.
Control.Concurrent.Async
should do what you want – Control.Parallel
is used for hinting which pure operations can be evaluated simultaneously, not for running multiple actions (monadic or otherwise) at the same time.
Upvotes: 6