This commit is contained in:
Carl Fredrik Samson
2020-02-02 19:05:33 +01:00
parent 49fe0ad893
commit 552f88919f

View File

@@ -27,7 +27,7 @@ handle concurrency:
I've written about green threads before. Go check out I've written about green threads before. Go check out
[Green Threads Explained in 200 lines of Rust][greenthreads] if you're interested. [Green Threads Explained in 200 lines of Rust][greenthreads] if you're interested.
Green threads uses the same mechanisms as an OS does by creating a thread for Green threads uses the same mechanism as an OS does by creating a thread for
each task, setting up a stack, save the CPU's state and jump from one each task, setting up a stack, save the CPU's state and jump from one
task(thread) to another by doing a "context switch". task(thread) to another by doing a "context switch".
@@ -36,8 +36,7 @@ such a system) which then continues running a different task.
Rust had green threads once, but they were removed before it hit 1.0. The state 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 of execution is stored in each stack so in such a solution there would be no need
for `async`, `await`, `Futures` or `Pin`. All this would be implementation for `async`, `await`, `Futures` or `Pin`. All this would be implementation details for the library.
details for the library.
### Combinators ### Combinators
@@ -64,8 +63,8 @@ While an effective solution there are mainly three downsides I'll focus on:
Point #3, is actually a major drawback with `Futures 1.0`. Point #3, is actually a major drawback with `Futures 1.0`.
Not allowing borrows across suspension points ends up being very Not allowing borrows across suspension points ends up being very
un-ergonomic and often requiring extra allocations or copying to accomplish un-ergonomic and to accomplish some tasks it requires extra allocations or
some tasks which is inefficient. copying which is inefficient.
The reason for the higher than optimal memory usage is that this is basically The reason for the higher than optimal memory usage is that this is basically
a callback-based approach, where each closure stores all the data it needs a callback-based approach, where each closure stores all the data it needs
@@ -94,10 +93,10 @@ async fn myfn() {
} }
``` ```
Generators are implemented as state machines. The memory footprint of a chain Generators in Rust are implemented as state machines. The memory footprint of a
of computations is only defined by the largest footprint any single step chain of computations is only defined by the largest footprint of any single
requires. That means that adding steps to a chain of computations might not step require. That means that adding steps to a chain of computations might not
require any added memory at all. require any increased memory at all.
## How generators work ## How generators work
@@ -380,8 +379,8 @@ to both possible undefined behavior and other memory errors while using just saf
Rust. This is a big problem! Rust. This is a big problem!
But now, let's prevent the segfault from happening using `Pin`. We'll discuss But now, let's prevent the segfault from happening using `Pin`. We'll discuss
`Pin` more below, but you'll get an introduction here by just reading the `Pin` more in the next chapter, but you'll get an introduction here by just
comments. reading the comments.
```rust,editable ```rust,editable
#![feature(optin_builtin_traits)] #![feature(optin_builtin_traits)]
@@ -394,11 +393,11 @@ pub fn main() {
// std::mem::swap(&mut gen, &mut gen2); // std::mem::swap(&mut gen, &mut gen2);
// constructing a `Pin::new()` on a type which does not implement `Unpin` is unsafe. // constructing a `Pin::new()` on a type which does not implement `Unpin` is unsafe.
// However, as I mentioned in the start of the next chapter about `Pin` a // However, as you'll see in the start of the next chapter value pinned to
// boxed type automatically implements `Unpin` so to stay in safe Rust we can use // heap can be constructed while staying in safe Rust so we can use
// that to avoid unsafe. You can also use crates like `pin_utils` to do this safely, // that to avoid unsafe. You can also use crates like `pin_utils` to do
// just remember that they use unsafe under the hood so it's like using an already-reviewed // this safely, just remember that they use unsafe under the hood so it's
// unsafe implementation. // like using an already-reviewed unsafe implementation.
let mut pinned1 = Box::pin(gen1); let mut pinned1 = Box::pin(gen1);
let mut pinned2 = Box::pin(gen2); let mut pinned2 = Box::pin(gen2);