spelling
This commit is contained in:
@@ -27,17 +27,16 @@ 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".
|
||||||
|
|
||||||
We yield control to the scheduler (which is a central part of the runtime in
|
We yield control to the scheduler (which is a central part of the runtime in
|
||||||
such a system) which then continues running a different task.
|
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
|
||||||
|
|
||||||
@@ -63,9 +62,9 @@ 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,15 +93,15 @@ 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
|
||||||
|
|
||||||
In Nightly Rust today you can use the `yield` keyword. Basically using this
|
In Nightly Rust today you can use the `yield` keyword. Basically using this
|
||||||
keyword in a closure, converts it to a generator. A closure looking like this
|
keyword in a closure, converts it to a generator. A closure looking like this
|
||||||
(I'm going to use the terminology that's currently in Rust):
|
(I'm going to use the terminology that's currently in Rust):
|
||||||
|
|
||||||
```rust,noplaypen,ignore
|
```rust,noplaypen,ignore
|
||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user