on master help sign in
Fix README and Overview.md

* Address review comments * Remove redundant parts in Overview.md that overlap with README

commitcf63b4edd45446d85ef06e7d71bf42ba2dcfd653 authorHarendra Kumar <harendra@composewell.com> dateThu 20 May 2021, 10:51 (5 years ago) parentdf676c6
2 files changed+53−199
README.md+49−58 docs/Overview.md+4−141
README.md+49−58
@@ -18,8 +18,8 @@
1818## Idiomatic Haskell at the speed of C
1919
2020Streamly is a Haskell library/framework providing basic building blocks
21−or combinators to perform fundamental as well as advanced programming
22−tasks with ease. The key features it provides are:
21+or combinators to build safe, scalable, modular and high performance
22+software systems. The key features it provides are:
2323
2424* Speed of C
2525* Safety of Haskell
@@ -43,10 +43,10 @@ repository](https://github.com/composewell/streamly-examples).
4343
4444## Modular Word Counting
4545
46−The `Fold` data type in streamly represents a consumer of stream. In
47−this example, we will use individual folds to count bytes, words and
48−lines in a file. We will see how these individual folds can be composed
49−together to do all the three at once with the same performance.
46+In this example, we will use folds to count bytes, words and lines in
47+a file. A `Fold` is a composable stream consumer. We will see how
48+individual folds can be composed together to perform all the three
49+counts at once with the same performance.
5050
5151See [WordCountModular.hs](https://github.com/composewell/streamly-examples/blob/master/examples/WordCountModular.hs)
5252for full working code including imports that we may have omitted
@@ -129,13 +129,10 @@ wc file =
129129 & Stream.fold countAll -- IO (Int, Int, Int)
130130```
131131
132−### Observations
133−
134−This example shows:
135−
136−* Excellent modularity
137−* Simple and concise API and types
138−* No bytestrings required, just streams of Word8
132+This example demonstrates the simple and concise API of streamly with
133+excellent modularity. Experienced Haskellers would notice that we have
134+not used bytestrings, we simply use a stream of `Word8`, simplifying the
135+program.
139136
140137## Performance
141138
@@ -165,7 +162,7 @@ sys 0m0.165s
165162
166163## Concurrent Word Counting
167164
168−To do word counting in parallel we divide the stream in chunks (arrays),
165+To count words in parallel we divide the stream into chunks (arrays),
169166count properties in each chunk and then add all the counts. We use the
170167same code as above except that we use an array input instead of using a
171168file input.
@@ -185,10 +182,12 @@ countArray arr =
185182 & Stream.decodeLatin1 -- SerialT IO Char
186183 & Stream.foldl' count (Counts 0 0 0 True) -- IO Counts
187184```
188−When combining the counts in two contiguous chunks, we would also need to
189−know whether the first element of the next chunk was a space char or
190−non-space to know whether the same word is continuing to the next chunk or
191−if it is a new word. So add that too, giving (firstCharWasSpace, Counts).
185+When combining the counts in two contiguous chunks, we would also need
186+to know whether the first element of the next chunk was a space char or
187+non-space to know whether the same word is continuing to the next chunk
188+or if it is a new word. `partialCounts` adds a `Bool` flag to `Counts`
189+returned by `countArray` to indicate whether the first character in the
190+chunk is a space.
192191
193192``` haskell
194193partialCounts :: Array Word8 -> IO (Bool, Counts)
@@ -224,7 +223,7 @@ wc file = do
224223 & Stream.foldl' addCounts (False, Counts 0 0 0 True) -- IO (Bool, Counts)
225224```
226225
227−Note that `Stream.aheadly` is the only difference in a concurrent and
226+Note that `Stream.fromAhead` is the only difference in a concurrent and
228227non-concurrent program. If we remove that we still have a perfectly valid,
229228well performing serial program. Notice, how succinctly and idiomatically
230229we expressed the concurrent word counting problem.
@@ -383,10 +382,6 @@ main = do
383382 & Stream.mapM_ print
384383```
385384
386−Notice, how succinctly and idiomatically we expressed the concurrent
387−directory tree traversal problem. Let us know if you can do it
388−significantly better with any other language or framework.
389−
390385## Rate Limiting
391386
392387For bounded concurrent streams, stream yield rate can be specified. For
@@ -438,13 +433,21 @@ documentation](https://streamly.composewell.com) to know more.
438433
439434## Concurrency
440435
441−Streamly uses lock-free synchronization for concurrent operations. It employs
442−auto-scaling of the degree of concurrency based on demand. For CPU bound tasks
443−it tries to keep the threads close to the number of CPUs available whereas for
444−IO bound tasks more threads can be utilized. Parallelism can be utilized with
445−little overhead even if the task size is very small. See [concurrency
446−benchmarks](https://github.com/composewell/concurrency-benchmarks) for detailed
447−performance results and a comparison with the `async` package.
436+Streamly uses lock-free synchronization for low overhead
437+concurrency. The number of tasks performed concurrently are
438+determined automatically based on the rate at which a consumer is
439+consuming the results. In other words, you do not need to manage
440+thread pools and decide how many threads to use for a particular
441+task. For CPU bound tasks it tries to keep the number of threads
442+close to the number of CPUs available whereas for IO bound tasks
443+more threads can be utilized.
444+
445+Parallelism can be utilized with little overhead even if
446+the task size is very small, because it can automatically
447+switch to serial mode or batch multiple tasks on the
448+same CPU if that is more efficient. See [concurrency
449+benchmarks](https://github.com/composewell/concurrency-benchmarks) for
450+detailed performance results and a comparison with the `async` package.
448451
449452## Performance
450453
@@ -452,41 +455,29 @@ As you have seen above in the word count example, streamly enables
452455highly modular abstractions with the best possible performance (close to
453456an equivalent C program).
454457
455−For example, none of the existing Haskell libraries can work with byte
456−level streams with acceptable performance. Streamly provides excellent
457−performance even for byte level stream operations, it is made possible
458−by employing efficient abstractions like `Unfold`s and terminating
459−`Fold`s. Byte level stream operations make programming simpler because
460−you do not have to deal with chunking and re-combining.
458+Streamly provides excellent performance even for byte level stream
459+operations, it is made possible by employing efficient abstractions like
460+`Unfold`s and terminating `Fold`s. Byte level stream operations make
461+programming simpler because you do not have to deal with chunking and
462+re-combining.
461463
462464If you can write a program significantly faster in some other way or
463−with some other language, please let us know and we will improve. We
464−still have some areas to improve but we will surely get there for most
465−cases.
465+with some other language, please let us know and we will improve.
466466
467467## Benchmarks
468468
469−When it comes to stream operations, Haskell lists is the fastest
470−existing implementation even though it supports only pure (not monadic)
471−streams. Other streaming libraries are many times slower compared to
472−lists, so lists is our gold standard for performance comparison.
473−
474−In the following chart, positive y-axis displays how many times worse
475−is a list operation compared to the corresponding streamly operation,
476−negative y-axis shows the same where streamly is worse compared to
477−lists.
478−
479−![Streamly vs Lists (time) comparison](charts-0/streamly-vs-list-time.svg)
480−
481−This chart show only those operations where streamly and list
482−performance differs by more than 10%. For all other operations the
483−performance of both is more or less comparable.
469+We measured several Haskell streaming implementations
470+on various micro-benchmarks. Please see [streaming
471+benchmarks](https://github.com/composewell/streaming-benchmarks) page
472+for detailed comparison of streamly with other streaming libraries.
484473
485−See [streaming
486−benchmarks](https://github.com/composewell/streaming-benchmarks) for
487−detailed comparison with other Haskell streaming libraries.
474+These results show that streamly is the fastest effectful streaming
475+implementation on almost all the measured micro benchmarks. In many cases
476+it is up to 100x faster and in some cases even 1000x faster. In many
477+composite operation benchmarks streamly turns out to be significantly
478+faster than the Haskell lists implementation.
488479
489−## Performance and Modularity
480+## Design Goals
490481
491482The goals of streamly from the very beginning have been, (1) simplicity
492483by unifying abstractions, (2) high performance. These are hard to
docs/Overview.md+4−141
@@ -1,19 +1,8 @@
1−# Streamly
1+## Overview
22
3−[![Hackage](https://img.shields.io/hackage/v/streamly.svg?style=flat)](https://hackage.haskell.org/package/streamly)
4−[![Gitter chat](https://badges.gitter.im/composewell/gitter.svg)](https://gitter.im/composewell/streamly)
5−[![Travis](https://travis-ci.com/composewell/streamly.svg?branch=master)](https://travis-ci.com/composewell/streamly)
6−[![Appveyor](https://ci.appveyor.com/api/projects/status/ajxg0c79raou9ned?svg=true)](https://ci.appveyor.com/project/harendra-kumar/streamly)
7−[![CircleCI](https://circleci.com/gh/composewell/streamly/tree/master.svg?style=svg)](https://circleci.com/gh/composewell/streamly/tree/master)
8−[![Coverage Status](https://coveralls.io/repos/composewell/streamly/badge.svg?branch=master&service=github)](https://coveralls.io/github/composewell/streamly?branch=master)
9−
10−## Learning Materials
11−
12−* Documentation: [Quick](#streaming-concurrently) | [Tutorial](https://hackage.haskell.org/package/streamly/docs/Streamly-Tutorial.html) | [Reference (Hackage)](https://hackage.haskell.org/package/streamly) | [Reference (Latest)](https://composewell.github.io/streamly) | [Guides](docs)
13−* Installing: [Installing](./INSTALL.md) | [Building for optimal performance](docs/Build.md)
14−* Examples: [streamly](examples) | [streamly-examples](https://github.com/composewell/streamly-examples)
15−* Benchmarks: [Streaming](https://github.com/composewell/streaming-benchmarks) | [Concurrency](https://github.com/composewell/concurrency-benchmarks)
16−* Talks: [Functional Conf 2019 Video](https://www.youtube.com/watch?v=uzsqgdMMgtk) | [Functional Conf 2019 Slides](https://www.slideshare.net/HarendraKumar10/streamly-concurrent-data-flow-programming)
3+These are some notes from an old version of README that may be
4+useful. For a quick introduction please read the README.md at the repo
5+root first.
176
187## Streaming Concurrently
198
@@ -71,45 +60,6 @@ computations, and the IO monad providing an escape hatch to an imperative
7160model, we just love to fall into the imperative trap, and start asking the same
7261fundamental question again - why do we have to use the streaming data model?
7362
74−## Comparative Performance
75−
76−High performance and simplicity are the two primary goals of streamly.
77−`Streamly` employs two different stream representations (CPS and direct style)
78−and interconverts between the two to get the best of both worlds on different
79−operations. It uses both foldr/build (for CPS style) and stream fusion (for
80−direct style) techniques to fuse operations. In terms of performance,
81−Streamly's goal is to compete with equivalent C programs. Streamly redefines
82−"blazing fast" for streaming libraries, it competes with lists and `vector`.
83−Other streaming libraries like "streaming", "pipes" and "conduit" are orders of
84−magnitude slower on most microbenchmarks. See [streaming
85−benchmarks](https://github.com/composewell/streaming-benchmarks) for detailed
86−comparison.
87−
88−The following chart shows a comparison of those streamly and list operations
89−where performance of the two differs by more than 10%. Positive y-axis displays
90−how many times worse is a list operation compared to the same streamly
91−operation, negative y-axis shows where streamly is worse compared to lists.
92−
93−![Streamly vs Lists (time) comparison](charts-0/streamly-vs-list-time.svg)
94−
95−Streamly uses lock-free synchronization for concurrent operations. It employs
96−auto-scaling of the degree of concurrency based on demand. For CPU bound tasks
97−it tries to keep the threads close to the number of CPUs available whereas for
98−IO bound tasks more threads can be utilized. Parallelism can be utilized with
99−little overhead even if the task size is very small. See [concurrency
100−benchmarks](https://github.com/composewell/concurrency-benchmarks) for detailed
101−performance results and a comparison with the `async` package.
102−
103−## Installing and using
104−
105−Please see [INSTALL.md](./INSTALL.md) for instructions on how to use streamly
106−with your Haskell build tool or package manager. You may want to go through it
107−before jumping to run the examples below.
108−
109−The module `Streamly.Prelude` provides the core stream types and combinators
110−for type casting, controlling concurrency, stream construction, transformation,
111−folding, merging, and zipping.
112−
11363## Streaming Pipelines
11464
11565The following snippet provides a simple stream composition example that reads
@@ -170,14 +120,6 @@ The following finishes in 10 seconds (100 seconds when serial):
170120S.drain $ S.fromAsync $ S.replicateM 10 $ p 10
171121```
172122
173−## Concurrency Auto Scaling
174−
175−Concurrency is auto-scaled i.e. more actions are executed concurrently if the
176−consumer is consuming the stream at a higher speed. How many tasks are executed
177−concurrently can be controlled by `maxThreads` and how many results are
178−buffered ahead of consumption can be controlled by `maxBuffer`. See the
179−documentation in the `Streamly.Prelude` module.
180−
181123## Concurrent Streaming Pipelines
182124
183125Use `|&` or `|$` to apply stream processing functions concurrently. The
@@ -306,39 +248,6 @@ main = do
306248 print s
307249```
308250
309−The concurrency facilities provided by streamly can be compared with
310−[OpenMP](https://en.wikipedia.org/wiki/OpenMP) and
311−[Cilk](https://en.wikipedia.org/wiki/Cilk) but with a more declarative
312−expression.
313−
314−## Example: Listing Directories Recursively/Concurrently
315−
316−The following code snippet lists a directory tree recursively, reading multiple
317−directories concurrently:
318−
319−```haskell
320−import Control.Monad.IO.Class (liftIO)
321−import Path.IO (listDir, getCurrentDir) -- from path-io package
322−import Streamly.Prelude (AsyncT, adapt)
323−import qualified Streamly.Prelude as S
324−
325−listDirRecursive :: AsyncT IO ()
326−listDirRecursive = getCurrentDir >>= readdir >>= liftIO . mapM_ putStrLn
327− where
328− readdir dir = do
329− (dirs, files) <- listDir dir
330− S.yield (map show dirs ++ map show files) <> foldMap readdir dirs
331−
332−main :: IO ()
333−main = S.drain $ adapt $ listDirRecursive
334−```
335−
336−`AsyncT` is a stream monad transformer. If you are familiar with a list
337−transformer, it is nothing but `ListT` with concurrency semantics. For example,
338−the semigroup operation `<>` is concurrent. This makes `foldMap` concurrent
339−too. You can replace `AsyncT` with `SerialT` and the above code will become
340−serial, exactly equivalent to a `ListT`.
341−
342251## Rate Limiting
343252
344253For bounded concurrent streams, stream yield rate can be specified. For
@@ -489,16 +398,6 @@ llhisto =
489398main = withArg llhisto >>= print
490399```
491400
492−## Socket IO
493−
494−Its easy to build concurrent client and server programs using streamly.
495−`Streamly.Network.*` modules provide easy combinators to build network servers
496−and client programs using streamly. See
497−[FromFileClient.hs](https://github.com/composewell/streamly/tree/master/examples/FromFileClient.hs),
498−[EchoServer.hs](https://github.com/composewell/streamly/tree/master/examples/EchoServer.hs),
499−[FileSinkServer.hs](https://github.com/composewell/streamly/tree/master/examples/FileSinkServer.hs)
500−in the examples directory.
501−
502401## Exceptions
503402
504403Exceptions can be thrown at any point using the `MonadThrow` instance. Standard
@@ -516,15 +415,6 @@ asynchronous exceptions to deal with. You can just ignore the zillions of
516415blogs, talks, caveats about async exceptions. Async exceptions just don't
517416exist. Please don't use things like `myThreadId` and `throwTo` just for fun!
518417
519−## Reactive Programming (FRP)
520−
521−Streamly is a foundation for first class reactive programming as well by virtue
522−of integrating concurrency and streaming. See
523−[AcidRain.hs](https://github.com/composewell/streamly/tree/master/examples/AcidRain.hs)
524−for a console based FRP game example and
525−[CirclingSquare.hs](https://github.com/composewell/streamly/tree/master/examples/CirclingSquare.hs)
526−for an SDL based animation example.
527−
528418## Conclusion
529419
530420Streamly, short for streaming concurrently, provides monadic streams, with a
@@ -577,30 +467,3 @@ streaming with concurrency we can write FRP applications similar in concept to
577467
578468See the `Comparison with existing packages` section at the end of the
579469[tutorial](https://hackage.haskell.org/package/streamly/docs/Streamly-Tutorial.html).
580−
581−## Support
582−
583−Please feel free to ask questions on the
584−[streamly gitter channel](https://gitter.im/composewell/streamly).
585−If you require professional support, consulting, training or timely
586−enhancements to the library please contact
587−[support@composewell.com](mailto:support@composewell.com).
588−
589−## Credits
590−
591−The following authors/libraries have influenced or inspired this library in a
592−significant way:
593−
594− * Roman Leshchinskiy ([vector](http://hackage.haskell.org/package/vector))
595− * Gabriel Gonzalez ([foldl](https://hackage.haskell.org/package/foldl))
596− * Alberto G. Corona ([transient](https://hackage.haskell.org/package/transient))
597−
598−See the `credits` directory for full list of contributors, credits and licenses.
599−
600−## Contributing
601−
602−The code is available under BSD-3 license
603−[on github](https://github.com/composewell/streamly). Join the [gitter
604−chat](https://gitter.im/composewell/streamly) channel for discussions. Please
605−ask any questions on the gitter channel or [contact the maintainer
606−directly](mailto:streamly@composewell.com). All contributions are welcome!