Skip to content

Commit 08e6ab9

Browse files
committed
Merge branch 'issue181' into async-chapter
2 parents 5c387fd + 665e898 commit 08e6ab9

File tree

6 files changed

+83
-15
lines changed

6 files changed

+83
-15
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,7 @@
232232
- [Async](async.md)
233233
- [async/await](async/async-await.md)
234234
- [Async Blocks](async/async-blocks.md)
235-
- Futures
236-
- Executors
237-
- Polling
238-
- Pin
235+
- [Futures](async/futures.md)
239236
- [Async Channels](async/channels.md)
240237
- [Futures Control Flow](async/control-flow.md)
241238
- [Exercises](exercises/day-4/async.md)

src/async/async-await.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

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

5-
```rust,editable
5+
```rust,editable,compile_fail
66
use tokio::time;
77
8-
async fn count_to(i: i32) {
9-
for i in 1..10 {
8+
async fn count_to(count: i32) {
9+
for i in 1..=count {
1010
println!("Count in task: {i}!");
1111
time::sleep(time::Duration::from_millis(5)).await;
1212
}

src/async/async-blocks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Similar to closures, a snippet of async code can be included inline in another
44
function with an async block:
55

6-
```rust, editable
6+
```rust,editable,compile_fail
77
use tokio::{time, task};
88
99
#[tokio::main]

src/async/channels.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
Multiple Channels crates have support for `async`/`await` read and write. For instance `tokio` channels:
44

5-
6-
```rust,editable
5+
```rust,editable,compile_fail
76
use tokio::sync::mpsc::{self, Receiver};
87
98
async fn ping_handler(mut input: Receiver<()>) {
109
let mut count: usize = 0;
11-
10+
1211
while let Some(_) = input.recv().await {
1312
count += 1;
1413
println!("Received {count} pings so far.");
@@ -22,7 +21,7 @@ async fn main() {
2221
for _ in 0..10 {
2322
sender.send(()).await.expect("Failed to send ping.");
2423
}
25-
24+
2625
std::mem::drop(sender);
2726
ping_handler_task.await.expect("Something went wrong in ping handler task.");
2827
}

src/async/control-flow.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ We will demonstrate here a non-exhaustive array of common operations:
1010
- JS: `Promise.all`
1111
- Python: `asyncio.gather`
1212

13-
```rust,editable
13+
```rust,editable,compile_fail
1414
use anyhow::Result;
1515
use futures::future;
1616
use reqwest;
@@ -44,7 +44,7 @@ async fn main() {
4444
- JS: `Promise.race`
4545
- Python: `asyncio.new_event_loop().run_until_complete(asyncio.wait(task_set, return_when=asyncio.FIRST_COMPLETED))`
4646

47-
```rust,editable
47+
```rust,editable,compile_fail
4848
use anyhow::Result;
4949
use tokio::sync::mpsc::{self, Receiver, Sender};
5050
use tokio::time::{sleep, Duration};
@@ -107,7 +107,7 @@ async fn main() {
107107

108108
## Iterate over multiple channels with a timeout: `select` with `pin`
109109

110-
```rust,editable
110+
```rust,editable,compile_fail
111111
use anyhow::Result;
112112
use tokio::sync::mpsc::{self, Receiver, Sender};
113113
use tokio::time::{sleep, Duration};

src/async/futures.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Futures
2+
3+
What is the type of an async operation?
4+
5+
```rust,editable,compile_fail
6+
use tokio::time;
7+
8+
async fn count_to(count: i32) -> i32 {
9+
for i in 1..=count {
10+
println!("Count in task: {i}!");
11+
time::sleep(time::Duration::from_millis(5)).await;
12+
}
13+
count
14+
}
15+
16+
#[tokio::main]
17+
async fn main() {
18+
let _: () = count_to(13);
19+
}
20+
```
21+
22+
[Future](https://doc.rust-lang.org/nightly/src/core/future/future.rs.html#37)
23+
is a trait, implemented by objects that represent an operation that may not be
24+
complete yet. A future can be polled, and `poll` returns either
25+
`Poll::Ready(result)` or `Poll::Pending`.
26+
27+
```rust
28+
use std::pin::Pin;
29+
use std::task::Context;
30+
31+
pub trait Future {
32+
type Output;
33+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
34+
}
35+
36+
pub enum Poll<T> {
37+
Ready(T),
38+
Pending,
39+
}
40+
```
41+
42+
An async function returns an `impl Future`, and an async block evaluates to an
43+
`impl Future`. It's also possible (but uncommon) to implement `Future` for your
44+
own types. For example, the `JoinHandle` returned from `tokio::spawn` implements
45+
`Future` to allow joining to it.
46+
47+
The `.await` keyword, applied to a Future, causes the current async function or
48+
block to pause until that Future is ready, and then evaluates to its output.
49+
50+
An important difference from other languages is that a Future is inert: it does
51+
not do anything until it is polled.
52+
53+
<details>
54+
55+
* Run the example and look at the error message. `_: () = ..` is a common
56+
technique for getting the type of an expression. Try adding a `.await` in
57+
`main`.
58+
59+
* The `Future` and `Poll` types are conceptually quite simple, and implemented as
60+
such in `std::task`.
61+
62+
* We will not get to `Pin` and `Context`, as we will focus on writing async
63+
code, rather than building new async primitives. Briefly:
64+
65+
* `Context` allows a Future to schedule itself to be polled again when an
66+
event occurs.
67+
68+
* `Pin` ensures that the Future isn't moved in memory, so that pointers into
69+
that future remain valid. This is required to allow references to remain
70+
valid after an `.await`.
71+
72+
</details>

0 commit comments

Comments
 (0)