[Haskell-cafe] monoid fold concurrently
Viktor Dukhovni
ietf-dane at dukhovni.org
Sat Nov 16 07:40:04 UTC 2019
On Fri, Nov 15, 2019 at 05:06:16PM -0500, Viktor Dukhovni wrote:
> I've not used this module myself, please post a summary of your
> experience.
I was curious, so I decided to try a simple case:
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE BangPatterns #-}
module Main (main) where
import Control.Concurrent.Async.Pool
import Control.Concurrent.STM
import Control.Monad
import Data.List
import Data.Monoid
import System.Environment
defCount, batchSz :: Int
defCount = 10000
batchSz = 256
batchList :: Int -> [a] -> [[a]]
batchList sz as = case splitAt sz as of
([], _) -> []
(t, []) -> [t]
(h, t) -> h : batchList sz t
main :: IO ()
main = do
n <- maybe defCount read <$> (fmap fst . uncons) <$> getArgs
let bs = batchList batchSz $ map Sum [1..n]
s <- foldM mergeReduce mempty bs
print $ getSum s
where
mergeReduce :: Sum Int -> [(Sum Int)] -> IO (Sum Int)
mergeReduce !acc ms = (acc <>) <$> reduceBatch (return <$> ms)
reduceBatch :: Monoid a => [IO a] -> IO a
reduceBatch ms =
withTaskGroup 8 $ (>>= wait) . atomically . flip mapReduce ms
Without batching, the whole list of actions is brought into memory,
all at once (to create the task dependency graph), and then the
outputs are folded concurrently, which does not run in constant
memory in the size of the list.
In the above the list of actions is chunked (256 at a time), these
are merged concurrently, but then the results from the chunks are
merged sequentially.
If the cost of storing the entire task list in memory is negligible,
a single mapReduce may perform better:
{-# LANGUAGE BlockArguments #-}
module Main (main) where
import Control.Concurrent.Async.Pool
import Control.Concurrent.STM
import Data.List
import Data.Monoid
import System.Environment
defCount :: Int
defCount = 100
main :: IO ()
main = do
n <- maybe defCount read <$> (fmap fst . uncons) <$> getArgs
withTaskGroup 8 \tg -> do
reduction <- atomically $ mapReduce tg $ map (return . Sum) [1..n]
wait reduction >>= print . getSum
--
Viktor.
More information about the Haskell-Cafe
mailing list