{-| Module : Control.Concurrent.Throttle Description : Limit the number of IO actions per second Copyright : (c) 2014, Rodrigo Setti License : MIT Maintainer : rodrigosetti@gmail.com Stability : experimental Portability : POSIX -} module Control.Concurrent.Throttle (throttle) where import Control.Concurrent import Control.Concurrent.MSemN import qualified Control.Concurrent.Thread as Thread import Control.Exception import Control.Monad -- | Limit the number of @tasks@ started per second. @throttle@ will run all -- actions concurrently but only starting a certain number per second. It -- will wait for all tasks and return the results in a list. throttle :: Int -- ^ number of tasks per second (TPS) -> [IO a] -- ^ the tasks to run concurrently but limited by TPS -> IO [a] -- ^ the tasks results throttle tps tasks = do sem <- new tps let runTask task = liftM snd $ wait sem 1 >> Thread.forkIO task timeResetWorker = forever $ threadDelay 1000000 >> signalF sem (\i -> (tps-i, ())) runAllTasks = mapM runTask tasks mapM Thread.result =<< sequence =<< bracket (forkIO timeResetWorker) killThread (const runAllTasks)