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.
|
runtime.
|
||||||
|
|
||||||
## Green threads/stackful coroutines
|
## Green threads/stackful coroutines
|
||||||
|
|
||||||
In this book I'll use the term "green threads" to mean stackful coroutines to differentiate
|
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
|
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
|
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
|
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
|
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
|
an operating system facilitates concurrency, and implementing them is a great
|
||||||
learning experience.
|
learning experience.
|
||||||
|
|
||||||
**The typical flow looks like this:**
|
**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.
|
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.
|
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
|
completion and that Rust’s Futures does not impose any restrictions on how you actually accomplish
|
||||||
this task.
|
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
|
supports this kind of supervision as well or else you will end up blocking the
|
||||||
executor.
|
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.
|
to the thread-pool most runtimes provide.
|
||||||
|
|
||||||
Most executors have a way to accomplish #1 using methods like `spawn_blocking`.
|
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
|
try to give a high-level overview that will make it easier to learn Rust's
|
||||||
Futures afterwards:
|
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 - 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 - 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 - 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 - 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
|
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.
|
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
|
[tokio]: https://github.com/tokio-rs/tokio
|
||||||
[compat_info]: https://rust-lang.github.io/futures-rs/blog/2019/04/18/compatibility-layer.html
|
[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
|
[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
|
> guarantees you normally get from the compiler. An `unsafe` implementation can
|
||||||
> be perfectly safe to do, but you have no safety net.
|
> be perfectly safe to do, but you have no safety net.
|
||||||
|
|
||||||
|
|
||||||
### Projection/structural pinning
|
### Projection/structural pinning
|
||||||
|
|
||||||
In short, projection is a programming language term. `mystruct.field1` is a
|
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
|
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.
|
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:**
|
**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 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.
|
// the `reactor` so it can wake us up when an event is ready.
|
||||||
let mywaker = Arc::new(MyWaker{ thread: thread::current() });
|
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
|
// 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.
|
// 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
|
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.
|
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
|
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
|
read all the way to the [Bonus Section](./6_future_example.md#bonus-section---a-proper-way-to-park-our-thread)
|
||||||
the end of this chapter.
|
at the end of this chapter.
|
||||||
|
|
||||||
For now, we keep it as simple and easy to understand as we can by just going
|
For now, we keep it as simple and easy to understand as we can by just going
|
||||||
to sleep.
|
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
|
> `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`
|
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.
|
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
|
`Pin` and the guarantees that give us to allow `Future`s to have self
|
||||||
references.
|
references.
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ const VTABLE: RawWakerVTable = unsafe {
|
|||||||
|
|
||||||
// Instead of implementing this on the `MyWaker` object in `impl Mywaker...` we
|
// 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.
|
// 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);
|
let raw_waker = RawWaker::new(s as *const (), &VTABLE);
|
||||||
unsafe { Waker::from_raw(raw_waker) }
|
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
|
can do so just pretend that this is actually represents some useful I/O operation
|
||||||
for the sake of this example.
|
for the sake of this example.
|
||||||
|
|
||||||
|
|
||||||
**Our Reactor will look like this:**
|
**Our Reactor will look like this:**
|
||||||
|
|
||||||
```rust, noplaypen, ignore
|
```rust, noplaypen, ignore
|
||||||
@@ -494,7 +493,7 @@ fn main() {
|
|||||||
# let mywaker = Arc::new(MyWaker {
|
# let mywaker = Arc::new(MyWaker {
|
||||||
# thread: thread::current(),
|
# 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);
|
# let mut cx = Context::from_waker(&waker);
|
||||||
#
|
#
|
||||||
# // SAFETY: we shadow `future` so it can't be accessed again.
|
# // 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);
|
# let raw_waker = RawWaker::new(s as *const (), &VTABLE);
|
||||||
# unsafe { Waker::from_raw(raw_waker) }
|
# 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
|
## 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`
|
sufficient to implement a proper reactor. You can also reach a tool like the `Parker`
|
||||||
in crossbeam: [crossbeam::sync::Parker][crossbeam_parker]
|
in crossbeam: [crossbeam::sync::Parker][crossbeam_parker]
|
||||||
|
|
||||||
|
|||||||
@@ -209,9 +209,7 @@ impl Drop for Reactor {
|
|||||||
|
|
||||||
## A little side note
|
## A little side note
|
||||||
|
|
||||||
The comments delimiting the Executor, `Future` implementation and Reactor,
|
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).
|
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,
|
Therefore, the comments associate the `Waker` with the `Future` implementation,
|
||||||
despite its strong relation with the Executor.
|
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/)
|
[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)
|
[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_std]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html
|
||||||
[condvar_wiki]: https://en.wikipedia.org/wiki/Monitor_(synchronization)#Condition_variables
|
[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
|
simple runtime in this book introducing some concepts but it's enough to get
|
||||||
started.
|
started.
|
||||||
|
|
||||||
[Stjepan Glavina](https://github.com/stjepang) has made an excellent series of
|
[Stjepan Glavina](https://web.archive.org/web/20200812203230/https://github.com/stjepang)
|
||||||
articles about async runtimes and executors, and if the rumors are right there
|
has made an excellent series of articles about async runtimes and executors,
|
||||||
is more to come from him in the near future.
|
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
|
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
|
reading [Stjepan's articles](https://web.archive.org/web/20200610130514/https://stjepang.github.io/)
|
||||||
about runtimes and how they work, especially:
|
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)
|
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)
|
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