@@ -48,6 +48,11 @@ import GHC.Prim (Any)
48import Asyncly.Threads
48import Asyncly.Threads
49import Asyncly.AsyncT
49import Asyncly.AsyncT
51+-- This transformer runs AsyncT under a state to manage the threads.
52+-- Separating the state from the pure ListT transformer is cleaner but it
53+-- results in 2x performance degradation. At some point if that performance is
54+-- really needed we can combine the two.
51newtype AsynclyT m a = AsynclyT { runAsynclyT :: AsyncT (StateT Context m) a }
56newtype AsynclyT m a = AsynclyT { runAsynclyT :: AsyncT (StateT Context m) a }
53deriving instance MonadAsync m => Functor (AsynclyT m)
58deriving instance MonadAsync m => Functor (AsynclyT m)
@@ -58,6 +63,10 @@ deriving instance MonadAsync m => MonadIO (AsynclyT m)
58instance MonadTrans (AsynclyT) where
63instance MonadTrans (AsynclyT) where
59 lift mx = AsynclyT $ AsyncT $ \s k -> lift mx >>= (\a -> (k a Nothing))
64 lift mx = AsynclyT $ AsyncT $ \s k -> lift mx >>= (\a -> (k a Nothing))
66+------------------------------------------------------------------------------
68+------------------------------------------------------------------------------
61getContext :: Maybe (IORef [Recording]) -> IO Context
70getContext :: Maybe (IORef [Recording]) -> IO Context
62getContext lref = do
71getContext lref = do
63 childChan <- atomically newTChan
72 childChan <- atomically newTChan
@@ -65,9 +74,9 @@ getContext lref = do
65 credit <- newIORef maxBound
74 credit <- newIORef maxBound
66 return $ initContext childChan pendingRef credit lref
75 return $ initContext childChan pendingRef credit lref
68−-- | Run an 'AsyncT m' computation, wait for it to finish and discard the
77+-- | Run an 'AsynclyT m' computation, wait for it to finish and discard the
69-- results.
78-- results.
70−{-# SPECIALIZE wait_ :: AsynclyT IO a -> IO () #-}
79+{-# INLINABLE wait_ #-}
71wait_ :: forall m a. (MonadAsync m, MonadCatch m) => AsynclyT m a -> m ()
80wait_ :: forall m a. (MonadAsync m, MonadCatch m) => AsynclyT m a -> m ()
72wait_ (AsynclyT m) = do
81wait_ (AsynclyT m) = do
73 ctx <- liftIO $ getContext Nothing
82 ctx <- liftIO $ getContext Nothing
@@ -76,31 +85,35 @@ wait_ (AsynclyT m) = do
79− run m = (runAsyncT m) (return ())
89+ run m = (runAsyncT m) stop (\_ r -> maybe stop run r)
80− (\a r -> maybe (return ()) (\x -> run x) r)
82data Step a r = Stop | Done a | Yield a r
91data Step a r = Stop | Done a | Yield a r
84−{-# SPECIALIZE wait :: AsynclyT IO a -> IO [a] #-}
93+{-# INLINABLE wait #-}
85−{-# INLINE wait #-}
94+-- | Run an 'AsynclyT m' computation and collect the results generated by each
95+-- thread of the computation in a list.
86wait :: forall m a. (MonadAsync m, MonadCatch m) => AsynclyT m a -> m [a]
96wait :: forall m a. (MonadAsync m, MonadCatch m) => AsynclyT m a -> m [a]
87wait (AsynclyT m) = liftIO (getContext Nothing) >>= run m
97wait (AsynclyT m) = liftIO (getContext Nothing) >>= run m
102+ done a = return (Done a)
103+ yield a x = return $ Yield a x
91 run ma ctx = do
105 run ma ctx = do
92− (res, ctx') <- runStateT ((runAsyncT ma) (return Stop)
106+ (res, ctx') <- runStateT
93− (\a r -> maybe (return (Done a)) (\x -> return $ Yield a x) r)) ctx
107+ ((runAsyncT ma) stop (\a r -> maybe (done a) (\x -> yield a x) r))
94 case res of
109 case res of
95 Yield x mb -> liftM (x :) (run mb ctx')
110 Yield x mb -> liftM (x :) (run mb ctx')
96− -- XXX pull from children here
97 Stop -> return []
111 Stop -> return []
98 Done x -> return (x : [])
112 Done x -> return (x : [])
100-- scatter
114-- scatter
101−{-# SPECIALIZE each :: [a] -> AsynclyT IO a #-}
115+{-# INLINABLE each #-}
102−each :: (MonadIO m, MonadBaseControl IO m, MonadThrow m)
103− => [a] -> AsynclyT m a
116+each :: MonadAsync m => [a] -> AsynclyT m a
104each xs = foldr (<|>) empty $ map return xs
117each xs = foldr (<|>) empty $ map return xs
106------------------------------------------------------------------------------
119------------------------------------------------------------------------------
@@ -114,95 +127,6 @@ each xs = foldr (<|>) empty $ map return xs
114-- threads n action = AsynclyT $ AsyncT $ threadCtl n (runAsyncT $ runAsynclyT action)
127-- threads n action = AsynclyT $ AsyncT $ threadCtl n (runAsyncT $ runAsynclyT action)
117−wait_ :: AsyncT IO a -> IO ()
119− ctx <- liftIO $ getContext (return :: a -> AsyncT IO a) Nothing
120− _ <- runStateT (run m) ctx
125− run m = runAsyncT m >>= \x ->
128− -- XXX pull from children here
131−wait :: forall m a. (MonadAsync m, MonadCatch m) => AsyncT m a -> m [a]
132−wait m = liftIO (getContext (return :: a -> AsyncT m a) Nothing) >>= run m
137− (a, ctx') <- runStateT (runAsyncT ma) ctx
139− Yield x mb -> liftM (x :) (run mb ctx')
140− -- XXX pull from children here
145−------------------------------------------------------------------------------
147−------------------------------------------------------------------------------
149−-- | Run an 'AsyncT m' computation and collect the results generated by each
150−-- thread of the computation in a list.
151−{-# SPECIALIZE waitAsync :: (a -> StateT Context IO (Maybe a))
152− -> Maybe (IORef [Recording]) -> AsyncT IO a -> IO () #-}
153−waitAsync :: (MonadAsync m, MonadCatch m)
154− => (a -> StateT Context m (Maybe a))
155− -> Maybe (IORef [Recording])
156− -> AsyncT m a -> m ()
157−waitAsync finalizer lref m = do
158− childChan <- liftIO $ atomically newTChan
159− pendingRef <- liftIO $ newIORef []
160− credit <- liftIO $ newIORef maxBound
162− let ctx = initContext childChan pendingRef credit finalizer lref
164− r <- try $ runStateT comp ctx
165− e <- handleResult ctx r
166− maybe (return ()) throwM e
171− maybe (return Nothing) finalizer x
173−-- TBD throttling of producer based on consumption rate.
175−-- | Invoked to store the result of the computation in the context and finish
176−-- the computation when the computation is done
177−{-# SPECIALIZE gatherResult :: IORef [a] -> a -> StateT Context IO (Maybe a) #-}
178−gatherResult :: MonadAsync m => IORef [a] -> a -> StateT Context m (Maybe a)
179−gatherResult ref r = do
180− liftIO $ atomicModifyIORefCAS ref $ \rs -> (r : rs, ())
183−gather :: (MonadAsync m, MonadCatch m)
185− -> StateT Context m (Maybe [a])
187− resultsRef <- liftIO $ newIORef []
188− lift $ waitAsync (gatherResult resultsRef) Nothing m
189− r <- liftIO $ readIORef resultsRef
192−-- | Run an 'AsyncT m' computation and collect the results generated by each
193−-- thread of the computation in a list.
194−{-# SPECIALIZE wait :: AsyncT IO a -> IO [a] #-}
195−wait :: (MonadAsync m, MonadCatch m) => AsyncT m a -> m [a]
197− resultsRef <- liftIO $ newIORef []
198− waitAsync (gatherResult resultsRef) Nothing m
199− liftIO $ readIORef resultsRef
201−-- | Run an 'AsyncT m' computation, wait for it to finish and discard the
203−wait_ :: (MonadAsync m, MonadCatch m) => AsyncT m a -> m ()
204−wait_ m = waitAsync (const (return Nothing)) Nothing m
206------------------------------------------------------------------------------
130------------------------------------------------------------------------------
207-- Logging
131-- Logging
208------------------------------------------------------------------------------
132------------------------------------------------------------------------------