started reworking the book based on feedback

This commit is contained in:
Carl Fredrik Samson
2020-02-06 23:35:06 +01:00
parent eda2f7dc59
commit a464846b73

View File

@@ -17,45 +17,62 @@ pretty simple. I promise.
Let's get some of the common roadblocks out of the way first. Let's get some of the common roadblocks out of the way first.
Async in Rust is different from most other languages in the sense that Rust Languages like C#, JavaScript, Java, GO and many others comes with a runtime
has a very lightweight runtime.
Languages like C#, JavaScript, Java and GO, already includes a runtime
for handling concurrency. So if you come from one of those languages this will for handling concurrency. So if you come from one of those languages this will
seem a bit strange to you. seem a bit strange to you.
In Rust you will have to make an active choice about which runtime to use. Rust is different from these languages in the sense that Rust doesn't come with
a runtime for handling concurrency, so you need to use a library which provide
this for you.
In other words you'll have to make an active choice about which runtime to use
which will of course seem foreign if the environment you come from provides one
which "everybody" uses.
### What Rust's standard library takes care of ### What Rust's standard library takes care of
1. The definition of an interruptible task 1. A common interface representing an operation which will be completed in the
2. An efficient technique to start, suspend, resume and store tasks which are future through the `Future` trait.
executed concurrently. 2. An ergonomic way of creating tasks which can be suspended and resumed through
3. A defined way to wake up a suspended task the `async` and `await` keywords.
3. A defined interface wake up a suspended task through the `Waker` trait.
That's really what Rusts standard library does. As you see there is no definition That's really what Rusts standard library does. As you see there is no definition
of non-blocking I/O, how these tasks are created or how they're run. of non-blocking I/O, how these tasks are created or how they're run.
### What you need to find elsewhere ### What you need to find elsewhere
A runtime. Well, in Rust we normally divide the runtime into two parts: A runtime, often just referred to as an `Executor`.
- The Reactor There are mainly two such runtimes in wide use in the community today
- The Executor [async_std][async_std] and [tokio][tokio].
Reactors create leaf `Futures`, and provides things like non-blocking sockets, Executors, accepts one or more asynchronous tasks (`Futures`) and takes
care of actually running the code we write, suspend the tasks when they're
waiting for I/O and resume them when they can make progress.
>Now, you might stumble upon articles/comments which mentions both an `Executor`
and an `Reactor` (also referred to as a `Driver`) as if they're well defined
concepts you need to know about. This is not true. In practice today you'll only
interface with the runtime, which provides leaf futures which actually wait for
some I/O operation, and the executor where
## Futures
Now, when we talk about futures I find it useful to make a distinction between
futures created by async functions `async fn() { ... }` and async blocks
`async { ... }` and **leaf** futures.
Runtimes create leaf `Futures`, and provides things like non-blocking sockets,
an event queue and so on. an event queue and so on.
Executors, accepts one or more asynchronous tasks called `Futures` and takes
care of actually running the code we write, suspend the tasks when they're
waiting for I/O and resume them.
In theory, we could choose one `Reactor` and one `Executor` that have nothing In theory, we could choose one `Reactor` and one `Executor` that have nothing
to do with each other besides that one creates leaf `Futures` and the other one to do with each other besides that one creates leaf `Futures` and the other one
runs them, but in reality today you'll most often get both in a `Runtime`. runs them, but in reality today you'll most often get both in a `Runtime`.
There are mainly two such runtimes today [async_std][async_std] and [tokio][tokio].
Quite a bit of complexity attributed to `Futures` are actually complexity rooted Quite a bit of complexity attributed to `Futures` are actually complexity rooted
in runtimes. Creating an efficient runtime is hard. in runtimes. Creating an efficient runtime is hard.