Skip to content

Add futures page #497

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,7 @@
- [Async](async.md)
- [async/await](async/async-await.md)
- [Async Blocks](async/async-blocks.md)
- Futures
- Executors
- Polling
- Pin
- Channels
- Select
- [Futures](async/futures.md)
- [Exercises](exercises/day-4/async.md)

# Final Words
Expand Down
6 changes: 3 additions & 3 deletions src/async/async-await.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

At a high level, async Rust code looks very much like "normal" sequential code:

```rust,editable
```rust,editable,compile_fail
use tokio::time;

async fn count_to(i: i32) {
for i in 1..10 {
async fn count_to(count: i32) {
for i in 1..=count {
println!("Count in task: {i}!");
time::sleep(time::Duration::from_millis(5)).await;
}
Expand Down
2 changes: 1 addition & 1 deletion src/async/async-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Similar to closures, a snippet of async code can be included inline in another
function with an async block:

```rust, editable
```rust,editable,compile_fail
use tokio::{time, task};

#[tokio::main]
Expand Down
72 changes: 72 additions & 0 deletions src/async/futures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Futures

What is the type of an async operation?

```rust,editable,compile_fail
use tokio::time;

async fn count_to(count: i32) -> i32 {
for i in 1..=count {
println!("Count in task: {i}!");
time::sleep(time::Duration::from_millis(5)).await;
}
count
}

#[tokio::main]
async fn main() {
let _: () = count_to(13);
}
```

[Future](https://doc.rust-lang.org/nightly/src/core/future/future.rs.html#37)
is a trait, implemented by objects that represent an operation that may not be
complete yet. A future can be polled, and `poll` returns either
`Poll::Ready(result)` or `Poll::Pending`.

```rust
use std::pin::Pin;
use std::task::Context;

pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}

pub enum Poll<T> {
Ready(T),
Pending,
}
```

An async function returns an `impl Future`, and an async block evaluates to an
`impl Future`. It's also possible (but uncommon) to implement `Future` for your
own types. For example, the `JoinHandle` returned from `tokio::spawn` implements
`Future` to allow joining to it.

The `.await` keyword, applied to a Future, causes the current async function or
block to pause until that Future is ready, and then evaluates to its output.

An important difference from other languages is that a Future is inert: it does
not do anything until it is polled.

<details>

* Run the example and look at the error message. `_: () = ..` is a common
technique for getting the type of an expression. Try adding a `.await` in
`main`.

* The `Future` and `Poll` types are conceptually quite simple, and implemented as
such in `std::task`.

* We will not get to `Pin` and `Context`, as we will focus on writing async
code, rather than building new async primitives. Briefly:

* `Context` allows a Future to schedule itself to be polled again when an
event occurs.

* `Pin` ensures that the Future isn't moved in memory, so that pointers into
that future remain valid. This is required to allow references to remain
valid after an `.await`.

</details>