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
[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
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
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
details for the library.
for `async`, `await`, `Futures` or `Pin`. All this would be implementation details for the library.
### 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`.
Not allowing borrows across suspension points ends up being very
un-ergonomic and often requiring extra allocations or copying to accomplish
some tasks which is inefficient.
un-ergonomic and to accomplish some tasks it requires extra allocations or
copying which is inefficient.
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
@@ -94,10 +93,10 @@ async fn myfn() {
}
```
Generators are implemented as state machines. The memory footprint of a chain
of computations is only defined by the largest footprint any single step
requires. That means that adding steps to a chain of computations might not
require any added memory at all.
Generators in Rust are implemented as state machines. The memory footprint of a
chain of computations is only defined by the largest footprint of any single
step require. That means that adding steps to a chain of computations might not
require any increased memory at all.
## 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!
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
comments.
`Pin` more in the next chapter, but you'll get an introduction here by just
reading the comments.
```rust,editable
#![feature(optin_builtin_traits)]
@@ -394,11 +393,11 @@ pub fn main() {
// std::mem::swap(&mut gen, &mut gen2);
// 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
// boxed type automatically implements `Unpin` so to stay in safe Rust we can use
// that to avoid unsafe. You can also use crates like `pin_utils` to do this safely,
// just remember that they use unsafe under the hood so it's like using an already-reviewed
// unsafe implementation.
// However, as you'll see in the start of the next chapter value pinned to
// 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, just remember that they use unsafe under the hood so it's
// like using an already-reviewed unsafe implementation.
let mut pinned1 = Box::pin(gen1);
let mut pinned2 = Box::pin(gen2);