Worker Pools in PureScript
Our example demonstrates how to implement a worker pool using PureScript’s asynchronous capabilities.
module Main where
import Prelude
import Effect (Effect)
import Effect.Console (log)
import Effect.Aff (Aff, launchAff_, delay)
import Effect.Class (liftEffect)
import Data.Array (range)
import Data.Int (toNumber)
import Control.Parallel (parallel, sequential)
-- Here's the worker function, of which we'll run several
-- concurrent instances. These workers will receive
-- work on the `jobs` array and return the corresponding
-- results. We'll use `delay` to simulate an expensive task.
worker :: Int -> Int -> Aff Int
worker id job = do
liftEffect $ log $ "worker " <> show id <> " started job " <> show job
delay $ 1000.0 -- Simulate work with a 1-second delay
liftEffect $ log $ "worker " <> show id <> " finished job " <> show job
pure $ job * 2
-- This function creates a worker that processes multiple jobs
createWorker :: Int -> Array Int -> Aff (Array Int)
createWorker id jobs = sequential $ map (parallel <<< worker id) jobs
main :: Effect Unit
main = launchAff_ do
let
numJobs = 5
jobs = range 1 numJobs
-- This starts up 3 workers, each processing a subset of the jobs
results <- sequential $
[ createWorker 1 [1, 4]
, createWorker 2 [2, 5]
, createWorker 3 [3]
]
-- Print the results
liftEffect $ log $ "Results: " <> show (join results)
In this PureScript version, we use the Aff
monad for asynchronous operations. The worker
function simulates work with a delay, and createWorker
processes multiple jobs for a single worker.
We create three workers, each handling a subset of the jobs. The parallel
and sequential
functions from Control.Parallel
are used to run the workers concurrently.
To run the program, you would typically use the PureScript compiler (purs
) and Node.js:
$ purs compile Main.purs
$ node -e "require('./output/Main').main()"
worker 1 started job 1
worker 2 started job 2
worker 3 started job 3
worker 1 finished job 1
worker 1 started job 4
worker 2 finished job 2
worker 2 started job 5
worker 3 finished job 3
worker 1 finished job 4
worker 2 finished job 5
Results: [2,8,4,10,6]
The program shows the 5 jobs being executed by various workers. It takes about 2 seconds to complete despite doing about 5 seconds of total work because there are 3 workers operating concurrently.
Note that PureScript’s approach to concurrency is different from traditional multithreading. It uses asynchronous operations and the Aff
monad to handle concurrent tasks, which is more similar to JavaScript’s event loop model than to OS-level threads.