I am playing with async library and trying to figure out its API in practice. I've noticed a strange behavior I didn't expect. It looks like a bug, but maybe it's a feature and I just need to know a workaround.
import Control.Concurrent
import Control.Concurrent.Async
> withAsync (putStrLn "HELLO") (\_ -> putStrLn "WORLD")
WORLHEDL
The snippet above is working just fine - both line lines executed, but more complex async body is evaluated partially.
> withAsync (putStrLn "XXXXXXXXXX" >> putStrLn "HELLO") (\_ -> putStrLn "WORLD")
WOXRXLXDX
See, the second putStrLn is not executed. I guess I need to wrap the whole async body in some sort of bnf, but it looks weird anyway. Why withAsync doesn't do that for me?
forkIO works just right, but I don't want to bother with unlifting. async has pair library unlift-async which propagates monad automatically.
forkIO (Prelude.putStrLn "XXXXXXXXXX" >> Prelude.putStrLn "HELLO")
ThreadXIXdX X1X1X3X
XXX
HELLO
I found lifted-base with fork function. It works as forkIO and pass parent monad to child thread.
withAsync
interrupts the forked thread (1st argument) when the main thread (2nd argument) terminates. This is explicit in the documentation of withAsync
:
When the function returns or throws an exception,
uninterruptibleCancel
is called on theAsync
.(...) This is a useful variant of
async
that ensures anAsync
is never left running unintentionally.
If you want to just fork a thread, use async
.
async (putStrLn "XXXXXXXX" >> putStrLn "WORLD") >> putStrLn "HELLO"