on 668f2ef help sign in
194 lines 6.3 kB history raw
1-- |
2-- Module : Streamly.Data.Stream.Concurrent
3-- Copyright : (c) 2022 Composewell Technologies
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
6-- Stability : released
7-- Portability : GHC
8--
9-- This module provides concurrent streaming abstractions.
10--
11-- == Programming Tips
12--
13-- The names in this module do not conflict with other stream modules,
14-- therefore, you can import it in the same namespace:
15--
16-- >>> import qualified Streamly.Data.Stream.Concurrent as Stream
18module Streamly.Data.Stream.Concurrent
19 (
20 -- * Concurrency
21 -- $concurrency
22 MonadAsync
24 -- ** Configuration
25 , Config
27 -- *** Limits
28 , maxThreads
29 , maxBuffer
31 -- *** Rate Control
32 , Rate(..)
33 , rate
34 , avgRate
35 , minRate
36 , maxRate
37 , constRate
39 -- *** Stop behavior
40 , StopWhen (..)
41 , stopWhen
43 -- *** Scheduling behavior
44 , eager
45 , ordered
46 , interleaved
48 -- *** Diagnostics
49 , inspect
51 -- ** Combinators
52 -- | Stream combinators using a concurrent channel.
54 -- *** Evaluate
55 -- | Evaluates a serial stream asynchronously using a concurency channel.
57 , parEval
59 -- *** Generate
60 -- | Uses a concurrency channel to evaluate multiple actions concurrently.
61 , parRepeatM
62 , parReplicateM
63 , fromCallback
65 -- *** Map
66 -- | Uses a concurrency channel to evaluate multiple mapped actions
67 -- concurrently.
69 , parMapM
70 , parSequence
72 -- *** Combine two
73 -- | Use a channel for each pair.
74 , parZipWithM
75 , parZipWith
76 , parMergeByM
77 , parMergeBy
79 -- *** List of streams
80 -- | Shares a single channel across many streams.
82 , parList
83 -- , zipWithM
84 -- , zipWith
86 -- *** Stream of streams
87 -- **** Apply
89 , parApply
91 -- **** Concat
92 -- | Shares a single channel across many streams.
94 , parConcat
95 , parConcatMap
97 -- **** ConcatIterate
98 , parConcatIterate
100 -- *** Observation
101 , parTapCount
103 -- ** Deprecated
104 , tapCount
105 )
106where
108import Streamly.Internal.Data.Stream.Concurrent
109import Prelude hiding (mapM, sequence, concat, concatMap, zipWith)
111-- $concurrency
112--
113-- == Concurrency Channels
114--
115-- At a lower level, concurrency is implemented using channels that support
116-- concurrent evaluation of streams. We create a channel, and add one or more
117-- streams to it. The channel evaluates multiple streams concurrently and then
118-- generates a single output stream from the results. How the streams are
119-- combined depends on the configuration of the channel.
120--
121-- == Concurrency Primitives
122--
123-- There are only a few fundamental abstractions for concurrency, 'parEval',
124-- 'parConcatMap', and 'parConcatIterate', all concurrency combinators can be
125-- expressed in terms of these.
126--
127-- 'parEval', evaluates a single stream asynchronously, a worker thread runs
128-- the stream and buffers the results, and the consumer of the stream runs in
129-- another thread consuming it from the buffer, thus decoupling the production
130-- and consumption of the stream. This can be used to run different stages of a
131-- pipeline concurrently.
132--
133-- 'parConcatMap' is used to evaluate multiple streams concurrently and combine
134-- the results. A stream generator function is mapped to the input stream and
135-- all the generated streams are then evaluated concurrently, and the results
136-- are combined.
137--
138-- 'parConcatIterate' is like 'parConcatMap' but iterates a stream generator
139-- function recursively over the stream. This can be used to traverse trees or
140-- graphs.
141--
142-- == Concurrency Configuration
143--
144-- Concurrent combinators take a 'Config' argument which controls the
145-- concurrent behavior. For example, maximum number of threads to be used
146-- ('maxThreads') or the maxmimum size of the buffer ('maxBuffer'), or how the
147-- streams are scheduled with respect to each other ('interleaved'), or how the
148-- results are consumed ('ordered').
149--
150-- Configuration is specified as @Config -> Config@ modifier functions that can
151-- be composed together using function composition. For example, to specify the
152-- maximum threads we can use @parConcatMap (maxThreads 10)@ if we also want to
153-- specify the maximum buffer we can compose the two options @parConcatMap
154-- (maxThreads 10 . maxBuffer 100)@. To use default configuration use 'id' as
155-- the config modifier e.g. @parConcatMap id@.
156--
157-- See the @Configuration@ section and individual configuration options'
158-- documentation for the default behavior and default values of configuration
159-- parameters.
160--
161-- == Scheduling behavior
162--
163-- The most important configuration option is to control whether the output of
164-- the concurrent execution is consumed in the same order as the corresponding
165-- actions in the input stream or as soon as they arrive. The default is the
166-- latter, however, we can enforce the original order by using the 'ordered'
167-- option.
168--
169-- Another important option controls whether the number of worker threads are
170-- automatically increased and decreased based on the consumption rate or
171-- threads are started as aggresively as possible until the 'maxThreads' or
172-- 'maxBuffer' limits are hit. The default is the former. However, the 'eager'
173-- option can be enabled to use the latter behavior. When 'eager' is on, even
174-- if the stream consumer thread blocks it does not make any impact on the
175-- scheduling of the available tasks.
176--
177-- == Concurrent Combinators
178--
179-- Using the few fundamental concurrency primitives we can implement all the
180-- usual streaming combinators with concurrent behavior. Combinators like
181-- 'unfoldrM', 'iterateM' that are inherently serial can be evaluated
182-- concurrently with respect to the consumer pipeline using 'parEval'.
183-- Combinators like 'zipWithM', 'mergeByM' can also use 'parEval' on the input
184-- streams to evaluate them concurrently before combining.
185--
186-- Combinators like 'repeatM', 'replicateM', 'fromListM', 'sequence', 'mapM' in
187-- which all actions are independent of each other can be made concurrent using
188-- the 'parConcatMap' operation.
189--
190-- A concurrent 'repeatM' repeats an action using multiple concurrent
191-- executions of the action. Similarly, a concurrent 'mapM' performs the mapped
192-- action in independent threads.
193--
194-- Some common concurrent combinators are provided in this module.