on e6cc89b help sign in
195 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
22 -- ** Types
23 MonadAsync
25 -- ** Configuration
26 , Config
28 -- *** Limits
29 , maxThreads
30 , maxBuffer
32 -- *** Rate Control
33 , Rate(..)
34 , rate
35 , avgRate
36 , minRate
37 , maxRate
38 , constRate
40 -- *** Stop behavior
41 , StopWhen (..)
42 , stopWhen
44 -- *** Scheduling behavior
45 , eager
46 , ordered
47 , interleaved
49 -- *** Diagnostics
50 , inspect
52 -- ** Combinators
53 -- | Stream combinators using a concurrent channel.
55 -- *** Evaluate
56 -- | Evaluates a serial stream asynchronously using a concurency channel.
58 , parEval
60 -- *** Generate
61 -- | Uses a concurrency channel to evaluate multiple actions concurrently.
62 , parRepeatM
63 , parReplicateM
64 , fromCallback
66 -- *** Map
67 -- | Uses a concurrency channel to evaluate multiple mapped actions
68 -- concurrently.
70 , parMapM
71 , parSequence
73 -- *** Combine two
74 -- | Use a channel for each pair.
75 , parZipWithM
76 , parZipWith
77 , parMergeByM
78 , parMergeBy
80 -- *** List of streams
81 -- | Shares a single channel across many streams.
83 , parList
84 -- , zipWithM
85 -- , zipWith
87 -- *** Stream of streams
88 -- **** Apply
90 , parApply
92 -- **** Concat
93 -- | Shares a single channel across many streams.
95 , parConcat
96 , parConcatMap
98 -- **** ConcatIterate
99 , parConcatIterate
101 -- *** Observation
102 , parTapCount
104 -- ** Deprecated
105 , tapCount
106 )
107where
109import Streamly.Internal.Data.Stream.Concurrent
110import Prelude hiding (mapM, sequence, concat, concatMap, zipWith)
112-- $concurrency
113--
114-- == Channels
115--
116-- At a lower level, concurrency is implemented using channels that support
117-- concurrent evaluation of streams. We create a channel, and add one or more
118-- streams to it. The channel evaluates multiple streams concurrently and then
119-- generates a single output stream from the results. How the streams are
120-- combined depends on the configuration of the channel.
121--
122-- == Primitives
123--
124-- There are only a few fundamental abstractions for concurrency, 'parEval',
125-- 'parConcatMap', and 'parConcatIterate', all concurrency combinators can be
126-- expressed in terms of these.
127--
128-- 'parEval', evaluates a single stream asynchronously, a worker thread runs
129-- the stream and buffers the results, and the consumer of the stream runs in
130-- another thread consuming it from the buffer, thus decoupling the production
131-- and consumption of the stream. This can be used to run different stages of a
132-- pipeline concurrently.
133--
134-- 'parConcatMap' is used to evaluate multiple streams concurrently and combine
135-- the results. A stream generator function is mapped to the input stream and
136-- all the generated streams are then evaluated concurrently, and the results
137-- are combined.
138--
139-- 'parConcatIterate' is like 'parConcatMap' but iterates a stream generator
140-- function recursively over the stream. This can be used to traverse trees or
141-- graphs.
142--
143-- == Configuration
144--
145-- Concurrent combinators take a 'Config' argument which controls the
146-- concurrent behavior. For example, maximum number of threads to be used
147-- ('maxThreads') or the maxmimum size of the buffer ('maxBuffer'), or how the
148-- streams are scheduled with respect to each other ('interleaved'), or how the
149-- results are consumed ('ordered').
150--
151-- Configuration is specified as @Config -> Config@ modifier functions that can
152-- be composed together using function composition. For example, to specify the
153-- maximum threads we can use @parConcatMap (maxThreads 10)@ if we also want to
154-- specify the maximum buffer we can compose the two options @parConcatMap
155-- (maxThreads 10 . maxBuffer 100)@. To use default configuration use 'id' as
156-- the config modifier e.g. @parConcatMap id@.
157--
158-- See the @Configuration@ section and individual configuration options'
159-- documentation for the default behavior and default values of configuration
160-- parameters.
161--
162-- == Scheduling
163--
164-- The most important configuration option is to control whether the output of
165-- the concurrent execution is consumed in the same order as the corresponding
166-- actions in the input stream or as soon as they arrive. The default is the
167-- latter, however, we can enforce the original order by using the 'ordered'
168-- option.
169--
170-- Another important option controls whether the number of worker threads are
171-- automatically increased and decreased based on the consumption rate or
172-- threads are started as aggresively as possible until the 'maxThreads' or
173-- 'maxBuffer' limits are hit. The default is the former. However, the 'eager'
174-- option can be enabled to use the latter behavior. When 'eager' is on, even
175-- if the stream consumer thread blocks it does not make any impact on the
176-- scheduling of the available tasks.
177--
178-- == Combinators
179--
180-- Using the few fundamental concurrency primitives we can implement all the
181-- usual streaming combinators with concurrent behavior. Combinators like
182-- 'unfoldrM', 'iterateM' that are inherently serial can be evaluated
183-- concurrently with respect to the consumer pipeline using 'parEval'.
184-- Combinators like 'zipWithM', 'mergeByM' can also use 'parEval' on the input
185-- streams to evaluate them concurrently before combining.
186--
187-- Combinators like 'repeatM', 'replicateM', 'fromListM', 'sequence', 'mapM' in
188-- which all actions are independent of each other can be made concurrent using
189-- the 'parConcatMap' operation.
190--
191-- A concurrent 'repeatM' repeats an action using multiple concurrent
192-- executions of the action. Similarly, a concurrent 'mapM' performs the mapped
193-- action in independent threads.
194--
195-- Some common concurrent combinators are provided in this module.