packages feed

hcheckers-0.1.0.2: src/Core/Parallel.hs

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Core.Parallel where

import Control.Monad
import Control.Monad.Except
import Control.Monad.Reader
import Control.Concurrent
import Data.Maybe
import qualified Data.Map as M
import qualified Data.Text as T
import System.Log.Heavy

import Core.Types

data Processor key input output = Processor (input -> key) (Chan (input, Chan (key, Either Error output)))

runProcessor :: Int -> (input -> key) -> (input -> Checkers output) -> Checkers (Processor key input output)
runProcessor nThreads getKey fn = do
    st <- ask
    inputChan <- liftIO newChan

    forM_ [1 .. nThreads] $ \i -> do
       liftIO $ forkIO $ worker st inputChan i
    return $ Processor getKey inputChan
  where
    worker st inChan i = forever $ do
      (input, outChan) <- readChan inChan
      output <- runCheckersT (withLogVariable "thread" (i :: Int) $ fn input) st
      writeChan outChan (getKey input, output)

runProcessor' :: [T.Text] -> (input -> key) -> (T.Text -> input -> Checkers output) -> Checkers (Processor key input output)
runProcessor' labels getKey fn = do
    st <- ask
    inputChan <- liftIO newChan

    forM_ labels $ \label -> do
       liftIO $ forkIO $ worker st inputChan label
    return $ Processor getKey inputChan
  where
    worker st inChan label = forever $ do
      (input, outChan) <- readChan inChan
      output <- runCheckersT (withLogVariable "thread" label $ fn label input) st
      writeChan outChan (getKey input, output)

process :: Ord key => Processor key input output -> [input] -> Checkers [output]
process processor inputs = do
    results <- process' processor inputs
    case sequence results of
      Right outputs -> return outputs
      Left err -> throwError err

process' :: Ord key => Processor key input output -> [input] -> Checkers [Either Error output]
process' (Processor getKey inChan) inputs = do
    let n = length inputs
    outChan <- liftIO newChan
    forM_ inputs $ \input ->
      liftIO $ writeChan inChan (input, outChan)
    results <- replicateM n $ liftIO $ readChan outChan
    let m = M.fromList results
    let results = [fromJust $ M.lookup (getKey input) m | input <- inputs]
    return results

processSingle :: Processor key input output -> input -> Checkers output
processSingle (Processor _ inChan) input = do
    outChan <- liftIO newChan
    liftIO $ writeChan inChan (input, outChan)
    result <- liftIO $ readChan outChan
    case snd result of
      Right output -> return output
      Left err -> throwError err