on master help sign in
Initial poc of lazy streaming
commit4d7024fae01c7707b9342c3f4326da19821aa894 authorHarendra Kumar <harendra.kumar@gmail.com> dateMon 7 Aug 2017, 15:15 (9 years ago) parent11c1f14
4 files changed+118−36
src/Asyncly.hs+6−6 src/Asyncly/AsyncT.hs+42−24 src/Asyncly/RunAsync.hs+57 src/Asyncly/Threads.hs+13−6
src/Asyncly.hs+6−6
@@ -129,10 +129,10 @@ module Asyncly
129129 , threads
130130
131131 -- * Fork and Gather
132− , async
133− , makeAsync
132+ --, async
133+ --, makeAsync
134134 , each
135− , gather
135+ --, gather
136136
137137 -- * Compose
138138 , before
@@ -143,9 +143,9 @@ module Asyncly
143143 , (>>|)
144144
145145 -- * Record and Play
146− , waitRecord
147− , waitRecord_
148− , playRecordings
146+ --, waitRecord
147+ --, waitRecord_
148+ --, playRecordings
149149 )
150150where
151151
src/Asyncly/AsyncT.hs+42−24
@@ -24,8 +24,8 @@ module Asyncly.AsyncT
2424 ( AsyncT (..)
2525
2626 , threads
27− , async
28− , makeAsync
27+-- , async
28+-- , makeAsync
2929 , each
3030
3131 , before
@@ -46,7 +46,7 @@ import Control.Monad.Base (MonadBase (..), liftBaseDefault)
4646import Control.Monad.Catch (MonadThrow, throwM)
4747import Control.Monad.State (MonadIO (..), MonadPlus (..),
4848 StateT (..), liftM, runStateT,
49− modify)
49+ get, gets, put, modify)
5050import Control.Monad.Trans.Class (MonadTrans (lift))
5151import Control.Monad.Trans.Control (ComposeSt, MonadBaseControl (..),
5252 MonadTransControl (..),
@@ -60,7 +60,8 @@ import Control.Monad.Trans.Recorder (MonadRecorder(..))
6060
6161import Asyncly.Threads
6262
63−newtype AsyncT m a = AsyncT { runAsyncT :: StateT Context m (Maybe a) }
63+--data Step a m = Stop | Yield a (AsyncT m a)
64+--newtype AsyncT m a = AsyncT { runAsyncT :: StateT Context m (Step a m) }
6465
6566------------------------------------------------------------------------------
6667-- Utilities
@@ -76,23 +77,38 @@ dbg _ = return ()
7677-- Monad
7778------------------------------------------------------------------------------
7879
80+stop :: Monad m => AsyncT m a
81+stop = AsyncT . return $ Stop
82+
83+{-# SPECIALIZE runAction :: AsyncT IO a -> StateT Context IO (Step a IO) #-}
84+runAction :: Monad m => AsyncT m a -> StateT Context m (Step a m)
85+runAction m = do
86+ ctx <- get
87+ (step, ctx') <- lift $ runStateT (runAsyncT m) ctx
88+ put ctx'
89+ return step
90+
91+-- TBD real parallel
92+{-# SPECIALIZE parallel :: AsyncT IO a -> AsyncT IO a -> StateT Context IO (Step a IO) #-}
93+parallel :: Monad m
94+ => AsyncT m a
95+ -> AsyncT m a
96+ -> StateT Context m (Step a m)
97+parallel ma mb = do
98+ step <- runAction ma
99+ case step of
100+ Stop -> runAsyncT mb
101+ Yield a mx -> return (Yield a (AsyncT (parallel mx mb)))
102+
79103instance MonadAsync m => Monad (AsyncT m) where
80104 {-# SPECIALIZE instance Monad (AsyncT IO) #-}
81− return a = AsyncT . return $ Just a
82− m >>= f = bind
83−
84− where
85−
86− {-# NOINLINE[1] bind #-}
87− bind = AsyncT $ do
88− modify $ \Context {continuations = fs, ..} ->
89− Context {continuations = (unsafeCoerce f) : fs, ..}
90− x <- runAsyncT m
91− modify $ \Context {continuations = (_ : fs), ..} ->
92− Context {continuations = fs, ..}
93− case x of
94− Just y -> runAsyncT $ f y
95− Nothing -> return Nothing
105+ return a = AsyncT . return $ Yield a stop
106+
107+ m >>= f = AsyncT $ do
108+ step <- runAction m
109+ case step of
110+ Stop -> return Stop -- XXX need to wait for the child threads
111+ Yield a ma -> runAsyncT $ (f a) <|> (ma >>= f)
96112
97113------------------------------------------------------------------------------
98114-- Functor
@@ -132,10 +148,8 @@ instance MonadAsync m => Applicative (AsyncT m) where
132148
133149instance MonadAsync m => Alternative (AsyncT m) where
134150 {-# SPECIALIZE instance Alternative (AsyncT IO) #-}
135− empty = AsyncT $ return Nothing
136− (<|>) m1 m2 = AsyncT $ do
137− r <- runAsyncTask False (runAsyncT m1)
138− maybe (runAsyncT m2) (return . Just) r
151+ empty = stop
152+ (<|>) m1 m2 = AsyncT $ parallel m1 m2
139153
140154instance MonadAsync m => MonadPlus (AsyncT m) where
141155 mzero = empty
@@ -162,7 +176,7 @@ instance (Num a, Monad (AsyncT m)) => Num (AsyncT m a) where
162176-------------------------------------------------------------------------------
163177
164178instance MonadTrans AsyncT where
165− lift mx = AsyncT $ lift mx >>= return . Just
179+ lift mx = AsyncT $ lift mx >>= return . (\a -> (Yield a stop))
166180
167181instance (MonadBase b m, MonadAsync m) => MonadBase b (AsyncT m) where
168182 liftBase = liftBaseDefault
@@ -171,6 +185,7 @@ instance (MonadBase b m, MonadAsync m) => MonadBase b (AsyncT m) where
171185-- monad-control
172186-------------------------------------------------------------------------------
173187
188+{-
174189instance MonadTransControl AsyncT where
175190 type StT AsyncT a = (Maybe a, Context)
176191 liftWith f = AsyncT $ StateT $ \s ->
@@ -186,6 +201,7 @@ instance (MonadBaseControl b m, MonadAsync m) => MonadBaseControl b (AsyncT m) w
186201 restoreM = defaultRestoreM
187202 {-# INLINABLE liftBaseWith #-}
188203 {-# INLINABLE restoreM #-}
204+-}
189205
190206------------------------------------------------------------------------------
191207-- Standard transformer instances
@@ -271,11 +287,13 @@ infixr 1 >>|
271287-- is not useful and should not be used. Even in an 'Alternative' composition
272288-- 'async' is not useful as the last action as the last action always runs in
273289-- the current thread.
290+{-
274291async :: MonadAsync m => AsyncT m a -> AsyncT m a
275292async action = AsyncT $ runAsyncTask True (runAsyncT action)
276293
277294makeAsync :: MonadAsync m => ((a -> m ()) -> m ()) -> AsyncT m a
278295makeAsync = AsyncT . makeCont
296+-}
279297
280298-- scatter
281299{-# SPECIALIZE each :: [a] -> AsyncT IO a #-}
src/Asyncly/RunAsync.hs+57
@@ -13,15 +13,18 @@
1313module Asyncly.RunAsync
1414 ( wait
1515 , wait_
16+ {-
1617 , gather
1718
1819 , waitRecord_
1920 , waitRecord
2021 , playRecordings
22+ -}
2123 )
2224where
2325
2426import Control.Concurrent.STM (atomically, newTChan)
27+import Control.Monad (liftM)
2528import Control.Monad.Catch (MonadCatch, throwM, try)
2629import Control.Monad.IO.Class (MonadIO (..))
2730import Control.Monad.State (StateT, runStateT)
@@ -34,6 +37,58 @@ import Control.Monad.Trans.Recorder (MonadRecorder(..), RecorderT,
3437import Asyncly.Threads
3538import Asyncly.AsyncT
3639
40+getContext :: Monad m => (a -> AsyncT m a) -> Maybe (IORef [Recording]) -> IO Context
41+getContext f lref = do
42+ childChan <- atomically newTChan
43+ pendingRef <- newIORef []
44+ credit <- newIORef maxBound
45+ return $ initContext childChan pendingRef credit f lref
46+
47+-- | Run an 'AsyncT m' computation, wait for it to finish and discard the
48+-- results.
49+wait_ :: forall m a. (MonadAsync m, MonadCatch m) => AsyncT m a -> m ()
50+wait_ m = do
51+ ctx <- liftIO $ getContext (return :: a -> AsyncT m a) Nothing
52+ _ <- runStateT (run m) ctx
53+ return ()
54+
55+ where
56+
57+ run m = runAsyncT m >>= \x ->
58+ case x of
59+ Yield _ r -> run r
60+ -- XXX pull from children here
61+ _ -> return ()
62+
63+{-
64+wait_ :: AsyncT IO a -> IO ()
65+wait_ m = do
66+ ctx <- liftIO $ getContext (return :: a -> AsyncT IO a) Nothing
67+ _ <- runStateT (run m) ctx
68+ return ()
69+
70+ where
71+
72+ run m = runAsyncT m >>= \x ->
73+ case x of
74+ Yield _ r -> run r
75+ -- XXX pull from children here
76+ _ -> return ()
77+-}
78+
79+wait :: forall m a. (MonadAsync m, MonadCatch m) => AsyncT m a -> m [a]
80+wait m = liftIO (getContext (return :: a -> AsyncT m a) Nothing) >>= run m
81+
82+ where
83+
84+ run ma ctx = do
85+ (a, ctx') <- runStateT (runAsyncT ma) ctx
86+ case a of
87+ Yield x mb -> liftM (x :) (run mb ctx')
88+ -- XXX pull from children here
89+ Stop -> return []
90+
91+{-
3792------------------------------------------------------------------------------
3893-- Running the monad
3994------------------------------------------------------------------------------
@@ -133,3 +188,5 @@ waitRecord_ m = do
133188 runRecorderT blank (waitAsync (const (return Nothing)) (Just lref) m)
134189 logs <- liftIO $ readIORef lref
135190 return logs
191+
192+-}
src/Asyncly/Threads.hs+13−6
@@ -15,16 +15,18 @@ module Asyncly.Threads
1515 ( -- ChildEvent(..)
1616 MonadAsync
1717 , Context(..)
18+ , Step (..)
19+ , AsyncT (..)
1820 , initContext
19− , runAsyncTask
20− , makeCont
21+ --, runAsyncTask
22+ --, makeCont
2123 , threadCtl
2224 -- , Location(..)
2325 -- , getLocation
2426 -- , setLocation
2527
2628 -- , waitForChildren
27− , handleResult
29+ --, handleResult
2830 )
2931where
3032
@@ -55,6 +57,9 @@ import Control.Monad.Trans.Recorder (Paused (..), Recording)
5557
5658type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m)
5759
60+data Step a m = Stop | Yield a (AsyncT m a)
61+newtype AsyncT m a = AsyncT { runAsyncT :: StateT Context m (Step a m) }
62+
5863------------------------------------------------------------------------------
5964-- Parent child thread communication types
6065------------------------------------------------------------------------------
@@ -128,7 +133,7 @@ initContext
128133 :: TChan ChildEvent
129134 -> IORef [ThreadId]
130135 -> IORef Int
131− -> (a -> StateT Context m (Maybe a))
136+ -> (a -> AsyncT m b)
132137 -> Maybe (IORef [Recording])
133138 -> Context
134139initContext childChan pending credit finalizer lref =
@@ -155,6 +160,7 @@ getLocation = gets location
155160setLocation :: Monad m => Location -> StateT Context m ()
156161setLocation loc = modify $ \Context { .. } -> Context { location = loc, .. }
157162
163+{-
158164------------------------------------------------------------------------------
159165-- Pick up from where we left in the previous thread
160166------------------------------------------------------------------------------
@@ -431,6 +437,7 @@ makeCont cbsetter = do
431437 return ()
432438 spawningParentDone
433439
440+-}
434441------------------------------------------------------------------------------
435442-- Controlling thread quota
436443------------------------------------------------------------------------------
@@ -441,8 +448,8 @@ makeCont cbsetter = do
441448-- 'async'.
442449threadCtl :: MonadAsync m
443450 => Int
444− -> StateT Context m (Maybe a)
445− -> StateT Context m (Maybe a)
451+ -> StateT Context m a
452+ -> StateT Context m a
446453threadCtl n action = do
447454 oldCr <- gets threadCredit
448455 newCr <- liftIO $ newIORef n