Merge pull request #44 from pedromfedricci/docfixes
Fix some links, names and linter warnings
This commit is contained in:
@@ -92,6 +92,7 @@ that they implement a way to do multitasking by having a "userland"
|
||||
runtime.
|
||||
|
||||
## Green threads/stackful coroutines
|
||||
|
||||
In this book I'll use the term "green threads" to mean stackful coroutines to differentiate
|
||||
them from the other continuation mechanisms described in this chapter. You can, however, see
|
||||
the term "green threads" be used to describe a broader set of continuation mechanisms in different
|
||||
@@ -108,7 +109,7 @@ Rust had green threads once, but they were removed before it hit 1.0. The state
|
||||
of execution is stored in each stack so in such a solution there would be no
|
||||
need for `async`, `await`, `Future` or `Pin`. In many ways, green threads mimics how
|
||||
an operating system facilitates concurrency, and implementing them is a great
|
||||
learning experience.
|
||||
learning experience.
|
||||
|
||||
**The typical flow looks like this:**
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ you'll just use the one provided for you.
|
||||
I find it easier to reason about how Futures work by creating a high level mental model we can use.
|
||||
To do that I have to introduce the concept of a runtime which will drive our Futures to completion.
|
||||
|
||||
>Please note that the mental model I create here is not the *only* way to drive Futures to
|
||||
>Please note that the mental model I create here is not the **only** way to drive Futures to
|
||||
completion and that Rust’s Futures does not impose any restrictions on how you actually accomplish
|
||||
this task.
|
||||
|
||||
@@ -217,7 +217,7 @@ The problem with #2 is that if you switch runtime you need to make sure that it
|
||||
supports this kind of supervision as well or else you will end up blocking the
|
||||
executor.
|
||||
|
||||
#3 is more of theoretical importance, normally you'd be happy by sending the task
|
||||
And #3 is more of theoretical importance, normally you'd be happy by sending the task
|
||||
to the thread-pool most runtimes provide.
|
||||
|
||||
Most executors have a way to accomplish #1 using methods like `spawn_blocking`.
|
||||
@@ -238,10 +238,10 @@ general, I know where you're coming from and I have written some resources to
|
||||
try to give a high-level overview that will make it easier to learn Rust's
|
||||
Futures afterwards:
|
||||
|
||||
* [Async Basics - The difference between concurrency and parallelism](https://cfsamson.github.io/book-exploring-async-basics/1_concurrent_vs_parallel.html)
|
||||
* [Async Basics - Async history](https://cfsamson.github.io/book-exploring-async-basics/2_async_history.html)
|
||||
* [Async Basics - Strategies for handling I/O](https://cfsamson.github.io/book-exploring-async-basics/5_strategies_for_handling_io.html)
|
||||
* [Async Basics - Epoll, Kqueue and IOCP](https://cfsamson.github.io/book-exploring-async-basics/6_epoll_kqueue_iocp.html)
|
||||
- [Async Basics - The difference between concurrency and parallelism](https://cfsamson.github.io/book-exploring-async-basics/1_concurrent_vs_parallel.html)
|
||||
- [Async Basics - Async history](https://cfsamson.github.io/book-exploring-async-basics/2_async_history.html)
|
||||
- [Async Basics - Strategies for handling I/O](https://cfsamson.github.io/book-exploring-async-basics/5_strategies_for_handling_io.html)
|
||||
- [Async Basics - Epoll, Kqueue and IOCP](https://cfsamson.github.io/book-exploring-async-basics/6_epoll_kqueue_iocp.html)
|
||||
|
||||
Learning these concepts by studying futures is making it much harder than
|
||||
it needs to be, so go on and read these chapters if you feel a bit unsure.
|
||||
@@ -307,4 +307,3 @@ understanding of what the concerns are.
|
||||
[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
|
||||
|
||||
|
||||
@@ -581,7 +581,6 @@ by adding `std::marker::PhantomPinned` to your type on stable.
|
||||
> guarantees you normally get from the compiler. An `unsafe` implementation can
|
||||
> be perfectly safe to do, but you have no safety net.
|
||||
|
||||
|
||||
### Projection/structural pinning
|
||||
|
||||
In short, projection is a programming language term. `mystruct.field1` is a
|
||||
|
||||
@@ -44,7 +44,7 @@ The first thing an `executor` does when it gets a `Future` is polling it.
|
||||
Rust provides a way for the Reactor and Executor to communicate through the `Waker`. The reactor stores this `Waker` and calls `Waker::wake()` on it once
|
||||
a `Future` has resolved and should be polled again.
|
||||
|
||||
> Notice that this chapter has a bonus section called [A Proper Way to Park our Thread](./6_future_example.md#bonus-section---a-proper-way-to-park-our-thread) which shows how to avoid `thread::park`.
|
||||
> Notice that this chapter has a bonus section called [A Proper Way to Park our Thread](./6_future_example.md#bonus-section---a-proper-way-to-park-our-thread) which shows how to avoid `thread::park`.
|
||||
|
||||
**Our Executor will look like this:**
|
||||
|
||||
@@ -55,7 +55,7 @@ fn block_on<F: Future>(mut future: F) -> F::Output {
|
||||
// the first thing we do is to construct a `Waker` which we'll pass on to
|
||||
// the `reactor` so it can wake us up when an event is ready.
|
||||
let mywaker = Arc::new(MyWaker{ thread: thread::current() });
|
||||
let waker = waker_into_waker(Arc::into_raw(mywaker));
|
||||
let waker = mywaker_into_waker(Arc::into_raw(mywaker));
|
||||
|
||||
// The context struct is just a wrapper for a `Waker` object. Maybe in the
|
||||
// future this will do more, but right now it's just a wrapper.
|
||||
@@ -89,10 +89,10 @@ In all the examples you'll see in this chapter I've chosen to comment the code
|
||||
extensively. I find it easier to follow along that way so I'll not repeat myself
|
||||
here and focus only on some important aspects that might need further explanation.
|
||||
|
||||
It's worth noting that simply calling `thread::sleep` as we do here can lead to
|
||||
It's worth noting that simply calling `thread::park` as we do here can lead to
|
||||
both deadlocks and errors. We'll explain a bit more later and fix this if you
|
||||
read all the way to the [Bonus Section](./6_future_example.md##bonus-section---a-proper-way-to-park-our-thread) at
|
||||
the end of this chapter.
|
||||
read all the way to the [Bonus Section](./6_future_example.md#bonus-section---a-proper-way-to-park-our-thread)
|
||||
at the end of this chapter.
|
||||
|
||||
For now, we keep it as simple and easy to understand as we can by just going
|
||||
to sleep.
|
||||
@@ -104,10 +104,10 @@ exact same challenges as we do when borrowing across `yield` points.
|
||||
|
||||
> `Context` is just a wrapper around the `Waker`. At the time of writing this
|
||||
book it's nothing more. In the future it might be possible that the `Context`
|
||||
object will do more than just wrapping a `Future` so having this extra
|
||||
object will do more than just wrapping a `Waker` so having this extra
|
||||
abstraction gives some flexibility.
|
||||
|
||||
As explained in the [chapter about generators](./3_generators_pin.md), we use
|
||||
As explained in the [chapter about Pin](./5_pin.md), we use
|
||||
`Pin` and the guarantees that give us to allow `Future`s to have self
|
||||
references.
|
||||
|
||||
@@ -175,7 +175,7 @@ const VTABLE: RawWakerVTable = unsafe {
|
||||
|
||||
// Instead of implementing this on the `MyWaker` object in `impl Mywaker...` we
|
||||
// just use this pattern instead since it saves us some lines of code.
|
||||
fn waker_into_waker(s: *const MyWaker) -> Waker {
|
||||
fn mywaker_into_waker(s: *const MyWaker) -> Waker {
|
||||
let raw_waker = RawWaker::new(s as *const (), &VTABLE);
|
||||
unsafe { Waker::from_raw(raw_waker) }
|
||||
}
|
||||
@@ -299,7 +299,6 @@ To be able to run the code here in the browser there is not much real I/O we
|
||||
can do so just pretend that this is actually represents some useful I/O operation
|
||||
for the sake of this example.
|
||||
|
||||
|
||||
**Our Reactor will look like this:**
|
||||
|
||||
```rust, noplaypen, ignore
|
||||
@@ -494,7 +493,7 @@ fn main() {
|
||||
# let mywaker = Arc::new(MyWaker {
|
||||
# thread: thread::current(),
|
||||
# });
|
||||
# let waker = waker_into_waker(Arc::into_raw(mywaker));
|
||||
# let waker = mywaker_into_waker(Arc::into_raw(mywaker));
|
||||
# let mut cx = Context::from_waker(&waker);
|
||||
#
|
||||
# // SAFETY: we shadow `future` so it can't be accessed again.
|
||||
@@ -542,7 +541,7 @@ fn main() {
|
||||
# )
|
||||
# };
|
||||
#
|
||||
# fn waker_into_waker(s: *const MyWaker) -> Waker {
|
||||
# fn mywaker_into_waker(s: *const MyWaker) -> Waker {
|
||||
# let raw_waker = RawWaker::new(s as *const (), &VTABLE);
|
||||
# unsafe { Waker::from_raw(raw_waker) }
|
||||
# }
|
||||
@@ -735,7 +734,7 @@ Don't forget the exercises in the last chapter 😊.
|
||||
|
||||
## Bonus Section - a Proper Way to Park our Thread
|
||||
|
||||
As we explained earlier in our chapter, simply calling `thread::sleep` is not really
|
||||
As we explained earlier in our chapter, simply calling `thread::park` is not really
|
||||
sufficient to implement a proper reactor. You can also reach a tool like the `Parker`
|
||||
in crossbeam: [crossbeam::sync::Parker][crossbeam_parker]
|
||||
|
||||
|
||||
@@ -209,9 +209,7 @@ impl Drop for Reactor {
|
||||
|
||||
## A little side note
|
||||
|
||||
The comments delimiting the Executor, `Future` implementation and Reactor,
|
||||
emphasize on what is part of the language (Future and Waker) and what is not (runtime specifics).
|
||||
The comments delimiting the Executor, `Future` implementation and Reactor,
|
||||
emphasize on what is part of the language (Future and Waker) and what is not (runtime specifics).
|
||||
Therefore, the comments associate the `Waker` with the `Future` implementation,
|
||||
despite its strong relation with the Executor.
|
||||
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ linked to in the book, here are some of my suggestions:
|
||||
|
||||
[The Tokio Blog](https://tokio.rs/blog/2019-10-scheduler/)
|
||||
|
||||
[Stjepan's blog with a series where he implements an Executor](https://stjepang.github.io/)
|
||||
[Stjepan's blog with a series where he implements an Executor](https://web.archive.org/web/20200207092849/https://stjepang.github.io/2020/01/31/build-your-own-executor.html)
|
||||
|
||||
[Jon Gjengset's video on The Why, What and How of Pinning in Rust](https://youtu.be/DkMwYxfSYNQ)
|
||||
|
||||
@@ -84,4 +84,4 @@ linked to in the book, here are some of my suggestions:
|
||||
|
||||
[condvar_std]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html
|
||||
[condvar_wiki]: https://en.wikipedia.org/wiki/Monitor_(synchronization)#Condition_variables
|
||||
[arcwake]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.13/futures/task/trait.ArcWake.html
|
||||
[arcwake]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.13/futures/task/trait.ArcWake.html
|
||||
|
||||
@@ -16,13 +16,13 @@ topic of different types of executors and runtimes. We'll just implement a very
|
||||
simple runtime in this book introducing some concepts but it's enough to get
|
||||
started.
|
||||
|
||||
[Stjepan Glavina](https://github.com/stjepang) has made an excellent series of
|
||||
articles about async runtimes and executors, and if the rumors are right there
|
||||
is more to come from him in the near future.
|
||||
[Stjepan Glavina](https://web.archive.org/web/20200812203230/https://github.com/stjepang)
|
||||
has made an excellent series of articles about async runtimes and executors,
|
||||
and if the rumors are right there is more to come from him in the near future.
|
||||
|
||||
The way you should go about it is to read this book first, then continue
|
||||
reading the [articles from stjepang](https://stjepang.github.io/) to learn more
|
||||
about runtimes and how they work, especially:
|
||||
reading [Stjepan's articles](https://web.archive.org/web/20200610130514/https://stjepang.github.io/)
|
||||
to learn more about runtimes and how they work, especially:
|
||||
|
||||
1. [Build your own block_on()](https://web.archive.org/web/20200511234503/https://stjepang.github.io/2020/01/25/build-your-own-block-on.html)
|
||||
2. [Build your own executor](https://web.archive.org/web/20200207092849/https://stjepang.github.io/2020/01/31/build-your-own-executor.html)
|
||||
|
||||
Reference in New Issue
Block a user