Waitgroups in Haskell
In Haskell, we can use the async
library to achieve similar functionality to WaitGroups. We’ll use Async
and Concurrently
to run multiple tasks concurrently and wait for them to finish.
import Control.Concurrent (threadDelay)
import Control.Concurrent.Async
import Control.Monad (forM_)
import Text.Printf (printf)
-- This is the function we'll run in every async task.
worker :: Int -> IO ()
worker id = do
printf "Worker %d starting\n" id
-- Sleep to simulate an expensive task.
threadDelay 1000000 -- 1 second
printf "Worker %d done\n" id
main :: IO ()
main = do
-- Run several tasks concurrently and wait for all of them to finish.
runConcurrently $ forM_ [1..5] $ \i ->
Concurrently $ worker i
-- Note that this approach automatically waits for all tasks to finish.
-- There's no need for an explicit "wait" call.
-- For more advanced use cases, consider using the
-- lifted-async package which provides more powerful
-- concurrency primitives.
To run the program:
$ runhaskell waitgroups.hs
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 4 starting
Worker 5 starting
Worker 1 done
Worker 2 done
Worker 3 done
Worker 4 done
Worker 5 done
The order of workers starting up and finishing is likely to be different for each invocation.
In this Haskell version:
We use the
async
library which provides high-level concurrency abstractions.The
worker
function is similar to the original, but usesthreadDelay
instead oftime.Sleep
.In the
main
function, we userunConcurrently
andConcurrently
to run multiple tasks concurrently. This replaces the explicit use of a WaitGroup.The
forM_
function is used to iterate over the range[1..5]
and create aConcurrently
task for each worker.Haskell’s type system ensures that all tasks are completed before the program exits, so there’s no need for an explicit “wait” call.
Error handling in concurrent Haskell code typically involves using
ExceptT
or similar monads. For more advanced concurrency patterns, thelifted-async
package provides additional tools.
This Haskell implementation showcases how functional languages can handle concurrency with high-level abstractions, often requiring less explicit synchronization code than imperative languages.