diff --git a/README.md b/README.md index e3fa54d0..bd8f2ee4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,11 @@ An implementation of [`IAsyncEnumerable<'T>`][3] as a computation expression: `taskSeq { ... }` with an accompanying `TaskSeq` module, that allows seamless use of asynchronous sequences similar to F#'s native `seq` and `task` CE's. -Latest version [can be installed from Nuget][nuget]. +Latest version [can be installed from Nuget][nuget]. + +## Release notes + +See [release notes.txt](release-notes.txt) for the version history of `TaskSeq`. See [Status overview](#status--planning) for current status of the surface area of `TaskSeq`. ----------------------------------------- @@ -24,15 +28,16 @@ Latest version [can be installed from Nuget][nuget]. - [`taskSeq` computation expressions](#taskseq-computation-expressions) - [Installation](#installation) - [Examples](#examples) -- [Status & planning](#status--planning) +- [Choosing between `AsyncSeq` and `TaskSeq`](#choosing-between-asyncseq-and-taskseq) +- [Status \& planning](#status--planning) - [Implementation progress](#implementation-progress) - [Progress `taskSeq` CE](#progress-taskseq-ce) - [Progress and implemented `TaskSeq` module functions](#progress-and-implemented-taskseq-module-functions) - [More information](#more-information) - - [Further reading `IAsyncEnumerable`](#further-reading-iasyncenumerable) + - [Further reading on `IAsyncEnumerable`](#further-reading-on-iasyncenumerable) - [Further reading on resumable state machines](#further-reading-on-resumable-state-machines) - [Further reading on computation expressions](#further-reading-on-computation-expressions) -- [Building & testing](#building--testing) +- [Building \& testing](#building--testing) - [Prerequisites](#prerequisites) - [Build the solution](#build-the-solution) - [Run the tests](#run-the-tests) @@ -163,9 +168,35 @@ let feedFromTwitter user pwd = taskSeq { } ``` +## Choosing between `AsyncSeq` and `TaskSeq` + +The [`AsyncSeq`][11] and `TaskSeq` libraries both operate on asynchronous sequences, but there are a few fundamental differences. The most notable being that the former _does not_ implement `IAsyncEnumerable<'T>`, though it does have a type of that name with different semantics (not surprising; it predates the definition of the modern one). Another key difference is that `TaskSeq` uses `ValueTask`s for the asynchronous computations, whereas `AsyncSeq` uses F#'s `Async<'T>`. + +There are more differences: + +| | `TaskSeq` | `AsyncSeq` | +|----------------------------|---------------------------------------------------------------------------------|----------------------------------------------------------------------| +| **Frameworks** | .NET 5.0+, NetStandard 2.1 | .NET 5.0+, NetStandard 2.0 and 2.1, .NET Framework 4.6.1+ | +| **Underlying type** | `System.Collections.Generic.IAsyncEnumerable<'T>` | Its own type, also called `IAsyncEnumerable<'T>`, but not compatible | +| **Implementation** | State machine (statically compiled) | No state machine, continuation style | +| **Semantics** | `seq`-like: on-demand | `seq`-like: on-demand | +| **Support `let!`** | All `task`-like: `Async<'T>`, `Task<'T>`, `ValueTask<'T>` or any `GetAwaiter()` | `Async<'T>` only | +| **Support `do!`** | `Async`, `Task` and `Task`, `ValueTask` and `ValueTask` | `Async` only | +| **Support `yield!`** | `IAsyncEnumerable<'T>`, `AsyncSeq`, any sequence | `AsyncSeq` | +| **Support `for`** | `IAsyncEnumerable<'T>`, `AsyncSeq`, any sequence | `AsyncSeq`, any sequence | +| **Behavior with `yield`** | Zero allocations; no `Task` or even `ValueTask` created | Allocates an F# `Async` wrapped in a singleton `AsyncSeq` | +| **Conversion to other** | `TaskSeq.toAsyncSeq` | `AsyncSeq.toAsyncEnum` | +| **Conversion from other** | Implicit (`yield!`) or `TaskSeq.ofAsyncSeq` | `AsyncSeq.ofAsyncEnum` | +| **Recursion in `yield!`** | **No** (requires F# support, upcoming) | Yes | +| **Based on F# concept of** | `task` | `async` | +| **`MoveNextAsync`** impl | `ValueTask` | `Async<'T option>` | +| **Cancellation** | Implicit token governs iteration | Implicit token flows to all subtasks per `async` semantics | +| **Performance** | Very high, negligible allocations | Slower, more allocations, due to using `async` | +| **Parallelism** | Possible with ChildTask; support will follow | Supported explicitly | + ## Status & planning -This project has stable features currently, but before we go full "version one", we'd like to complete the surface area. This section covers the status of that, with a full list of implmented functions below. Here's the short list: +This project has stable features currently, but before we go full "version one", we'd like to complete the surface area. This section covers the status of that, with a full list of implemented functions below. Here's the shortlist: - [x] Stabilize and battle-test `taskSeq` resumable code. **DONE** - [x] A growing set of module functions `TaskSeq`, see below for progress. **DONE & IN PROGRESS** @@ -330,12 +361,6 @@ The following is the progress report: ## More information -### The AsyncSeq library - -If you're looking to use `IAsyncEnumerable` with `async` and not `task`, the existing [`AsyncSeq`][11] library already provides excellent coverage of that use case. While `TaskSeq` is intended to interoperate with `async` as `task` does, it's not intended to provide an `AsyncSeq` type (at least not yet). - -In short, if your application is using `Async` (and the parallelism features stemming from that), consider using the `AsyncSeq` library instead. - ### Further reading on `IAsyncEnumerable` - A good C#-based introduction [can be found in this blog][8]. diff --git a/release-notes.txt b/release-notes.txt index b17a305b..a7559384 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -2,6 +2,7 @@ Release notes: 0.4.x (unreleased) - adds TaskSeq.takeWhile, takeWhileAsync, takeWhileInclusive, takeWhileInclusiveAsync, #126 (by @bartelink) + - adds AsyncSeq vs TaskSeq comparison chart, #131 0.3.0 - internal renames, improved doc comments, signature files for complex types, hide internal-only types, fixes #112.