Search code examples
multithreadinghaskelljobs

Haskell Job Pool


I'm interested in Haskell programming, but I'd want to create a job pool system, and I wonder if that will be a problem in Haskell.

Below is a simple program in Ruby. On one thread of execution, words are taken from a user and added to a list. On another thread, words are taken from the list and processed in some way (in this case, reversed and printed back to the user).

words = []

# Create new thread to take words from array, one at a time, and process them
t = Thread.new {
  loop do
    unless words.empty?
      word = words.pop
      break if word == 'quit'
      sleep 1
      puts word.reverse
    end
  end
}

# Take words from user and add to array
loop do
  puts "Enter word:"
  word = gets.chomp
  words << word
  break if word == 'quit'
end

t.join

What is the equivalent Haskell code?


Solution

  • Here's a pretty close translation.

    Chan is a FIFO queue for message passing between Haskell threads.

    Below I use a MVar for waiting that the spooler has exited. This is like a regular mutable variable, but it is protected with a mutex. It can either be empty (only a put is allowed, takes wait) or full (only a take is allowed, puts wait).

    I also use Haskell threads below, which might be run on separate OS-level threads or not -- the Haskell runtime chooses that. Haskell threads are very cheap, compared with OS threads.

    See e.g. Real World Haskell for more discussion.

    {-# OPTIONS -Wall #-}
    module JobPool where
    
    import Control.Monad (when)
    import Control.Concurrent
    
    spooler :: Chan String -> MVar () -> IO ()
    spooler ch stop = do
       word <- readChan ch
       if word == "quit"
       then putMVar stop ()
       else do
          threadDelay 1000000 -- us
          putStrLn (reverse word)
          spooler ch stop
    
    main :: IO ()
    main = do
       stop <- newEmptyMVar
       ch <- newChan
       _ <- forkIO $ spooler ch stop
       let loop = do
              word <- getLine
              writeChan ch word
              when (word /= "quit") loop
       loop
       takeMVar stop