@@ -23,6 +23,8 @@ module Streamly.Streams.Parallel
23 , Parallel
23 , Parallel
24 , parallely
24 , parallely
25 , parallel
25 , parallel
27 -- * Function application
29 -- * Function application
28 , mkParallel
30 , mkParallel
@@ -42,10 +44,13 @@ import Control.Monad.Reader.Class (MonadReader(..))
42import Control.Monad.State.Class (MonadState(..))
44import Control.Monad.State.Class (MonadState(..))
43import Control.Monad.Trans.Class (MonadTrans(lift))
45import Control.Monad.Trans.Class (MonadTrans(lift))
44import Data.Functor (void)
46import Data.Functor (void)
47+import Data.IORef (readIORef, writeIORef)
45import Data.Maybe (fromJust)
48import Data.Maybe (fromJust)
46import Data.Semigroup (Semigroup(..))
49import Data.Semigroup (Semigroup(..))
47import Prelude hiding (map)
50import Prelude hiding (map)
52+import qualified Data.Set as Set
49import Streamly.Streams.SVar (fromSVar)
54import Streamly.Streams.SVar (fromSVar)
50import Streamly.Streams.Serial (map)
55import Streamly.Streams.Serial (map)
51import Streamly.SVar
56import Streamly.SVar
@@ -88,22 +93,28 @@ runOne st m winfo = foldStreamShared st yieldk single stop m
88 >> withLimitCheck (void $ liftIO $ mrun $ runOne st r winfo)
93 >> withLimitCheck (void $ liftIO $ mrun $ runOne st r winfo)
90{-# NOINLINE forkSVarPar #-}
95{-# NOINLINE forkSVarPar #-}
91−forkSVarPar :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
96+forkSVarPar :: (IsStream t, MonadAsync m)
97+ => SVarStopStyle -> t m a -> t m a -> t m a
92−forkSVarPar m r = mkStream $ \st yld sng stp -> do
98+forkSVarPar ss m r = mkStream $ \st yld sng stp -> do
93− sv <- newParallelVar st
99+ sv <- newParallelVar ss st
94 pushWorkerPar sv (runOne st{streamVar = Just sv} $ toStream m)
100 pushWorkerPar sv (runOne st{streamVar = Just sv} $ toStream m)
102+ StopBy -> liftIO $ do
103+ set <- readIORef (workerThreads sv)
104+ writeIORef (svarStopBy sv) $ Set.elemAt 0 set
95 pushWorkerPar sv (runOne st{streamVar = Just sv} $ toStream r)
106 pushWorkerPar sv (runOne st{streamVar = Just sv} $ toStream r)
96 foldStream st yld sng stp (fromSVar sv)
107 foldStream st yld sng stp (fromSVar sv)
98{-# INLINE joinStreamVarPar #-}
109{-# INLINE joinStreamVarPar #-}
99joinStreamVarPar :: (IsStream t, MonadAsync m)
110joinStreamVarPar :: (IsStream t, MonadAsync m)
100− => SVarStyle -> t m a -> t m a -> t m a
111+ => SVarStyle -> SVarStopStyle -> t m a -> t m a -> t m a
101−joinStreamVarPar style m1 m2 = mkStream $ \st yld sng stp ->
112+joinStreamVarPar style ss m1 m2 = mkStream $ \st yld sng stp ->
102 case streamVar st of
113 case streamVar st of
103− Just sv | svarStyle sv == style -> do
114+ Just sv | svarStyle sv == style && svarStopStyle sv == ss -> do
104 pushWorkerPar sv (runOne st $ toStream m1)
115 pushWorkerPar sv (runOne st $ toStream m1)
105 foldStreamShared st yld sng stp m2
116 foldStreamShared st yld sng stp m2
106− _ -> foldStreamShared st yld sng stp (forkSVarPar m1 m2)
117+ _ -> foldStreamShared st yld sng stp (forkSVarPar ss m1 m2)
108-- | XXX we can implement it more efficienty by directly implementing instead
119-- | XXX we can implement it more efficienty by directly implementing instead
109-- of combining streams using parallel.
120-- of combining streams using parallel.
@@ -118,7 +129,28 @@ consMParallel m r = fromStream $ K.yieldM m `parallel` (toStream r)
118-- @since 0.2.0
129-- @since 0.2.0
119{-# INLINE parallel #-}
130{-# INLINE parallel #-}
120parallel :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
131parallel :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
121−parallel = joinStreamVarPar ParallelVar
132+parallel = joinStreamVarPar ParallelVar StopNone
134+-- This is a co-parallel like combinator for streams, where first stream is the
135+-- main stream and the rest are just supporting it, when the first ends
138+-- | Like `parallel` but stops the output as soon as the first stream stops.
141+{-# INLINE parallelEndByFirst #-}
142+parallelEndByFirst :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
143+parallelEndByFirst = joinStreamVarPar ParallelVar StopBy
145+-- This is a race like combinator for streams.
147+-- | Like `parallel` but stops the output as soon as any of the two streams
151+{-# INLINE parallelEndByAny #-}
152+parallelEndByAny :: (IsStream t, MonadAsync m) => t m a -> t m a -> t m a
153+parallelEndByAny = joinStreamVarPar ParallelVar StopAny
123------------------------------------------------------------------------------
155------------------------------------------------------------------------------
124-- Convert a stream to parallel
156-- Convert a stream to parallel
@@ -126,7 +158,7 @@ parallel = joinStreamVarPar ParallelVar
127mkParallel :: (IsStream t, MonadAsync m) => t m a -> m (t m a)
159mkParallel :: (IsStream t, MonadAsync m) => t m a -> m (t m a)
128mkParallel m = do
160mkParallel m = do
129− sv <- newParallelVar defState
161+ sv <- newParallelVar StopNone defState
130 pushWorkerPar sv (runOne defState{streamVar = Just sv} $ toStream m)
162 pushWorkerPar sv (runOne defState{streamVar = Just sv} $ toStream m)
131 return $ fromSVar sv
163 return $ fromSVar sv
@@ -137,7 +169,7 @@ mkParallel m = do
137{-# INLINE applyParallel #-}
169{-# INLINE applyParallel #-}
138applyParallel :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> t m a -> t m b
170applyParallel :: (IsStream t, MonadAsync m) => (t m a -> t m b) -> t m a -> t m b
139applyParallel f m = mkStream $ \st yld sng stp -> do
171applyParallel f m = mkStream $ \st yld sng stp -> do
140− sv <- newParallelVar (adaptState st)
172+ sv <- newParallelVar StopNone (adaptState st)
141 pushWorkerPar sv (runOne st{streamVar = Just sv} (toStream m))
173 pushWorkerPar sv (runOne st{streamVar = Just sv} (toStream m))
142 foldStream st yld sng stp $ f $ fromSVar sv
174 foldStream st yld sng stp $ f $ fromSVar sv
@@ -148,7 +180,7 @@ applyParallel f m = mkStream $ \st yld sng stp -> do
148{-# INLINE foldParallel #-}
180{-# INLINE foldParallel #-}
149foldParallel :: (IsStream t, MonadAsync m) => (t m a -> m b) -> t m a -> m b
181foldParallel :: (IsStream t, MonadAsync m) => (t m a -> m b) -> t m a -> m b
150foldParallel f m = do
182foldParallel f m = do
151− sv <- newParallelVar defState
183+ sv <- newParallelVar StopNone defState
152 pushWorkerPar sv (runOne defState{streamVar = Just sv} $ toStream m)
184 pushWorkerPar sv (runOne defState{streamVar = Just sv} $ toStream m)
153 f $ fromSVar sv
185 f $ fromSVar sv