Skip to content

Add AsyncSeq vs TaskSeq comparison readme #131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 16, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,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)
Expand Down Expand Up @@ -163,6 +164,33 @@ let feedFromTwitter user pwd = taskSeq {
}
```

## Choosing between `AsyncSeq` and `TaskSeq`

The [`AsyncSeq`][11] and `TaskSeq` library both operate on asynchronous sequences, but there are a few fundamental differences, most notably that the former _does not_ implement `IAsyncEnumerable<'T>`, but has its own same-named, but differently behaving type. Another core difference is that `TaskSeq` uses `ValueTasks` for the asynchronous computations, and `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>`, `ValueTask<'T>`, `Task<'T>` or any `GetAwaiter()` | `Async<'T>` only |
| **Support `do!`** | `Async<unit>`, `Task<unit>` and `Task`, `ValueTask<unit>` and `ValueTask` | `Async<unit>` 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 | Allocated, 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`** | `ValueTask<bool>` | `Async<'T option>` |
| **`Current` internals** | `ValueOption<'T>` | `Option<'T>` |
| **Cancellation** | Implicit token governing iteration | Implicit token passed to each subtask |
| **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:
Expand Down Expand Up @@ -330,12 +358,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].
Expand Down