diff --git a/src/0_0_Introduction.md b/src/0_0_Introduction.md index 370f0b3..54337a3 100644 --- a/src/0_0_Introduction.md +++ b/src/0_0_Introduction.md @@ -5,82 +5,39 @@ This book aims to explain `Futures` in Rust using an example driven approach. The goal is to get a better understanding of `Futures` by implementing a toy `Reactor`, a very simple `Executor` and our own `Futures`. -We'll start off a bit untraditionally. Instead of deferring some of the details about what's -special about futures in Rust we try to tackle that head on first. We'll be as brief as possible, -but as thorough as needed. I findt that implementing and understanding `Futures` is a lot easier -then. Actually, most questions will be answered up front. +We'll start off a bit differently than most other explanations. Instead of +deferring some of the details about what's special about futures in Rust we +try to tackle that head on first. We'll be as brief as possible, but as thorough +as needed. This way, most question will be answered and explored up front. We'll end up with futures that can run an any executor like `tokio` and `async_str`. -In the end I've made some reader excercises you can do if you want to fix some -of the most glaring ommissions and shortcuts we took and create a slightly better +In the end I've made some reader exercises you can do if you want to fix some +of the most glaring omissions and shortcuts we took and create a slightly better example yourself. ## What does this book give you that isn't covered elsewhere? That's a valid question. There are many good resources and examples already. First -of all, this book will point you to some background information that I have found -very valuable, especially `Generators` and stackless coroutines. +of all, this book will focus on `Futures` and `async/await` specifically and +not in the context of any specific runtime. -I find that many discussions arise, not because `Futures` is a hard concept to -grasp, but that concurrent programming is a hard concept in general. - -Secondly, I've always found small runnable examples very exiting to learn from. It's +Secondly, I've always found small runnable examples very exiting to learn from. +Thanks to Mdbook the examples can even be edited and explored further. It's all code that you can download, play with and learn from. -## What we'll do and not +We'll and end up with an understandable example including a `Future` +implementation, an `Executor` and a `Reactor` in less than 200 lines of code. +We don't rely on any dependencies or real I/O which means it's very easy to +explore further and try your own ideas. -**We'll:** - -- Implement our own `Futures` and get to know the `Reactor/Executor` pattern -- Implement our own waker and learn why it's a bit foreign compared to other types -- Talk a bit about runtime complexity and what to keep in mind when writing async Rust. -- Make sure all examples can be run on the playground -- Not rely on any helpers or libraries, but try to face the complexity and learn - -**We'll not:** - -- Talk about how futures are implemented in Rust the language, the state machine and so on -- Explain how the different runtimes differ, however, you'll hopefully be a bit -better off if you read this before you go research them -- Explain concurrent programming, but I will supply sources - -I do want to explore Rusts internal implementation but that will be for a later -book. ## Credits and thanks I'll like to take the chance of thanking the people behind `mio`, `tokio`, `async_std`, `Futures`, `libc`, `crossbeam` and many other libraries which so much is built upon. Reading and exploring some of this code is nothing less than -impressive. - -## Why is `Futures` in Rust hard to understand - -Well, I think it has to do with several things: - -1. Futures has a very interesting implementation, compiling down to a state -machine using generators to suspend and resume execution. In a language such as -Rust this is pretty hard to do ergonomically and safely. You are exposed to some -if this complexity when working with futures and want to understand them, not -only learn how to use them. - -2. Rust doesn't provide a runtime. That means you'll actually have to choose one -yourself and actually know what a `Reactor` and an `Executor` is. While not -too difficult, you need to make more choices than you need in GO and other -languages designed with a concurrent programming in mind and ships with a -runtime. - -3. Futures exist in two versions, Futures 1.0 and Futures 3.0. Futures 1.0 was -known to have some issues regarding ergonomics. Turns out that modelling -async coding after `Promises` in JavaScript can turn in to extremely long errors -and type signatures with a type system as Rust. - -Futures 3.0 are not compatible with Futures 1.0 without performing some work. - -4. Async await syntax was recently stabilized - -what we'll -really do is to stub out a `Reactor`, and `Executor` and implement +impressive. Even the RFCs that much of the design is built upon is written in a +way that mortal people can understand, and that requires a lot of work. So thanks! diff --git a/src/1_0_background_information.md b/src/1_0_background_information.md index ec30e22..13b09c6 100644 --- a/src/1_0_background_information.md +++ b/src/1_0_background_information.md @@ -6,6 +6,75 @@ information that will help demystify some of the concepts we encounter. Actually, after going through these concepts, implementing futures will seem pretty simple. I promise. +## Async in Rust + +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 +has an extremely lightweight runtime. + +In languages like C#, JavaScript, Java and GO, the runtime is already there. So +if you come from one of those languages this will seem a bit strange to you. + +### What Rust's standard library takes care of + +1. The definition of an interruptible task +2. An extremely efficient technique to start, suspend, resume and store tasks +which are executed concurrently. +3. A defined way to wake up a suspended task + +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. + + +### What you need to find elsewhere + +A runtime. Well, in Rust we normally divide the runtime into two parts: + +- The Reactor +- The Executor + +Reactors create leaf `Futures`, and provides things like non-blocking sockets, +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 resumes them. + +In theory, we could choose one `Reactor` and one `Executor` that have nothing +to do with each other besides one creates leaf `Futures` and one 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 +in runtimes. Creating an efficient runtime is hard. Learning how to use one +correctly can be hard as well, but both are excellent and it's just like +learning any new library. + +The difference between Rust and other languages is that you have to make an +active choice when it comes to picking a runtime. Most often you'll just use +the one provided for you. + +## Futures 1.0 and Futures 3.0 + +I'll not spend too much time on this, but it feels wrong to not mention that +there have been several iterations on how async should work in Rust. + +`Futures 3.0` works with the relatively new `async/await` syntax in Rust and +it's what we'll learn. + +Now, since this is rather recent, you can encounter creates that use `Futures 1.0` +still. This will get resolved in time, but unfortunately it's not always easy +to know in advance. + +A good sign is that if you're required to use combinators like `and_then` then +you're using `Futures 1.0`. + +While not directly compatible, there is a tool that let's you relatively easily +convert a `Future 1.0` to a `Future 3.0` and vice a verca. You can find all you +need in the [`futures-rs`][futures_rs] crate and all [information you need here][compat_info]. + ## First things first If you find the concepts of concurrency and async programming confusing in @@ -29,4 +98,9 @@ learn are: 2. Generators/stackless coroutines 3. Pinning, what it is and why we need it -Let's get moving! \ No newline at end of file +Let's get moving! + +[async_std]: https://github.com/async-rs/async-std +[tokio]: https://github.com/tokio-rs/tokio +[compat_info]: https://rust-lang.github.io/futures-rs/blog/2019/04/18/compatibility-layer.html +[futures_rs]: https://github.com/rust-lang/futures-rs \ No newline at end of file