Skip to content

Commit 6ee9c87

Browse files
authored
Merge branch 'issue181' into async-chapter
2 parents fa32983 + 1cff6e3 commit 6ee9c87

File tree

5 files changed

+104
-3
lines changed

5 files changed

+104
-3
lines changed

src/SUMMARY.md

+2
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@
233233
- [async/await](async/async-await.md)
234234
- [Async Blocks](async/async-blocks.md)
235235
- [Futures](async/futures.md)
236+
- [Runtimes](async/runtimes.md)
237+
- [Tasks](async/tasks.md)ures](async/futures.md)
236238
- [Async Channels](async/channels.md)
237239
- [Futures Control Flow](async/control-flow.md)
238240
- [Daemon](async/control-flow/daemon.md)

src/async/futures.md

-3
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,6 @@ own types. For example, the `JoinHandle` returned from `tokio::spawn` implements
4747
The `.await` keyword, applied to a Future, causes the current async function or
4848
block to pause until that Future is ready, and then evaluates to its output.
4949

50-
An important difference from other languages is that a Future is inert: it does
51-
not do anything until it is polled.
52-
5350
<details>
5451

5552
* Run the example and look at the error message. `_: () = ..` is a common

src/async/runtimes.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Runtimes and Tasks
2+
3+
A *runtime* provides support for performing operations asynchronously (a
4+
*reactor*) and is responsible for executing futures (an *executor*). Rust does not have a
5+
"built-in" runtime, but several options are available:
6+
7+
* [Tokio](https://tokio.rs/) - performant, with a well-developed ecosystem of
8+
functionality like [Hyper](https://hyper.rs/) for HTTP or
9+
[Tonic](https://github.com/hyperium/tonic) for gRPC.
10+
* [async-std](https://async.rs/) - aims to be a "std for async", and includes a
11+
basic runtime in `async::task`.
12+
* [smol](https://docs.rs/smol/latest/smol/) - simple and lightweight
13+
14+
Several larger applications have their own runtimes. For example,
15+
[Fuchsia](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/fuchsia-async/src/lib.rs)
16+
already has one.
17+
18+
<details>
19+
20+
* Note that of the listed runtimes, only Tokio is supported in the Rust
21+
playground. The playground also does not permit any I/O, so most interesting
22+
async things can't run in the playground.
23+
24+
* Futures are "inert" in that they do not do anything (not even start an I/O
25+
operation) unless there is an executor polling them. This differs from JS
26+
Promises, for example, which will run to completion even if they are never
27+
used.
28+
29+
</details>

src/async/tasks.md

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Tasks
2+
3+
Runtimes have the concept of a "Task", similar to a thread but much
4+
less resource-intensive.
5+
6+
A Task has a single top-level Future which the executor polls to make progress.
7+
That future may have one or more nested futures that its `poll` method polls,
8+
corresponding loosely to a call stack. Concurrency is possible within a task by
9+
polling multiple child futures, such as racing a timer and an I/O operation.
10+
11+
```rust,editable,compile_fail
12+
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
13+
use tokio::net::TcpListener;
14+
15+
#[tokio::main]
16+
async fn main() -> io::Result<()> {
17+
let listener = TcpListener::bind("127.0.0.1:6142").await?;
18+
println!("listening on port 6142");
19+
20+
loop {
21+
let (mut socket, addr) = listener.accept().await?;
22+
23+
println!("connection from {addr:?}");
24+
25+
tokio::spawn(async move {
26+
if let Err(e) = socket.write_all(b"Who are you?\n").await {
27+
println!("socket error: {e:?}");
28+
return;
29+
}
30+
31+
let mut buf = vec![0; 1024];
32+
let reply = match socket.read(&mut buf).await {
33+
Ok(n) => {
34+
let name = std::str::from_utf8(&buf[..n]).unwrap().trim();
35+
format!("Thanks for dialing in, {name}!\n")
36+
}
37+
Err(e) => {
38+
println!("socket error: {e:?}");
39+
return;
40+
}
41+
};
42+
43+
if let Err(e) = socket.write_all(reply.as_bytes()).await {
44+
println!("socket error: {e:?}");
45+
}
46+
});
47+
}
48+
}
49+
```
50+
51+
<details>
52+
53+
Copy this example into your prepared `src/main.rs` and run it from there.
54+
55+
* Ask students to visualize what the state of the example server would be with a
56+
few connected clients. What tasks exist? What are their Futures?
57+
58+
* Refactor the async block into a function, and improve the error handling using `?`.
59+
60+
</details>

src/running-the-course/day-4.md

+13
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,18 @@ Ensure that `adb sync` works with your emulator or real device and pre-build
2323
all Android examples using `src/android/build_all.sh`. Read the script to see
2424
the commands it runs and make sure they work when you run them by hand.
2525

26+
## Async
27+
28+
If you chose Async for Day 4 afternoon, you will need a fresh crate set up and
29+
the dependencies downloaded and ready to go. You can then copy/paste the
30+
examples into `src/main.rs` to experiment with them.
31+
32+
```shell
33+
cargo init day4
34+
cd day4
35+
cargo add tokio --features full
36+
cargo run
37+
```
38+
2639
[1]: https://source.android.com/docs/setup/download/downloading
2740
[2]: https://github.com/google/comprehensive-rust

0 commit comments

Comments
 (0)