Skip to content

Commit 7f50737

Browse files
committed
Add exercise async1
The goal here was to get the first bit of "muscle memory" for using the async and await keywords. The little story should make it more intuitive for users why asynchronous programming is needed in the first place. This exercise will be moved to the location corresponding to the book in a later commit, to keep the diff of this one clean.
1 parent b730882 commit 7f50737

5 files changed

Lines changed: 149 additions & 0 deletions

File tree

dev/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ bin = [
188188
{ name = "try_from_into_sol", path = "../solutions/23_conversions/try_from_into.rs" },
189189
{ name = "as_ref_mut", path = "../exercises/23_conversions/as_ref_mut.rs" },
190190
{ name = "as_ref_mut_sol", path = "../solutions/23_conversions/as_ref_mut.rs" },
191+
{ name = "async1", path = "../exercises/24_async/async1.rs" },
192+
{ name = "async1_sol", path = "../solutions/24_async/async1.rs" },
191193
]
192194

193195
[package]
@@ -196,6 +198,9 @@ edition = "2024"
196198
# Don't publish the exercises on crates.io!
197199
publish = false
198200

201+
[dependencies]
202+
tokio = { version = "1.52.1", features = ["rt"] }
203+
199204
[profile.release]
200205
panic = "abort"
201206

exercises/24_async/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Async
2+
3+
Asynchronous programming is a model where tasks are delegated to a runtime that executes them concurrently.
4+
It is particularly efficient for applications where many independent IO-operations are performed, e.g. web servers.
5+
6+
Rust provides the necessary primitives to do asynchronous programming in the language.
7+
However, Rust's standard library does not include a runtime.
8+
For these exercises, we will use the popular runtime called `tokio`.
9+
10+
## Further information
11+
12+
- [Fundamentals of Asynchronous Programming](https://doc.rust-lang.org/book/ch17-00-async-await.html)
13+
- [Tokio documentation](https://docs.rs/tokio/latest/tokio/)

exercises/24_async/async1.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Tim has to complete a few chores today, before he's allowed to play soccer
2+
// with his friends. His friends decide to help him. Working together, they
3+
// finish the chores earlier and have more time left to play soccer.
4+
//
5+
// Let's simulate this using asynchronous programming. Each boy is represented
6+
// as an asynchronous task, which can be executed concurrently (they can be
7+
// working at the same time).
8+
9+
use std::sync::atomic::{AtomicU8, Ordering};
10+
11+
fn do_chores() {
12+
// Async tasks need to be executed by a "runtime", which is not provided by
13+
// Rust's standard library. We use the popular "tokio" runtime here.
14+
let rt = tokio::runtime::Builder::new_current_thread()
15+
.build()
16+
.unwrap();
17+
18+
// TODO: Fix the compiler errors by making the spawned function async.
19+
let task_tim = rt.spawn(tim());
20+
let task_carl = rt.spawn(carl());
21+
let task_nick = rt.spawn(nick());
22+
23+
// Block the runtime on a task that waits for all boys to finish the chores.
24+
// TODO: "await" all three tasks to fix the compiler errors.
25+
rt.block_on(async {
26+
task_tim;
27+
task_carl;
28+
task_nick;
29+
});
30+
31+
assert_eq!(
32+
CHORES_DONE.load(Ordering::SeqCst),
33+
3,
34+
"Did you (a)wait for all the boys to finish the chores?"
35+
);
36+
println!("Ready to play soccer!");
37+
}
38+
39+
/// Used by "mom" to check that all chores are done before Tim plays soccer :-)
40+
static CHORES_DONE: AtomicU8 = AtomicU8::new(0);
41+
42+
fn tim() {
43+
println!("Cleaning my room...");
44+
CHORES_DONE.fetch_add(1, Ordering::SeqCst);
45+
}
46+
47+
fn carl() {
48+
println!("Washing the dishes...");
49+
CHORES_DONE.fetch_add(1, Ordering::SeqCst);
50+
}
51+
52+
fn nick() {
53+
println!("Mowing the lawn...");
54+
CHORES_DONE.fetch_add(1, Ordering::SeqCst);
55+
}
56+
57+
fn main() {
58+
do_chores();
59+
}

rustlings-macros/info.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,3 +1199,17 @@ name = "as_ref_mut"
11991199
dir = "23_conversions"
12001200
hint = """
12011201
Add `AsRef<str>` or `AsMut<u32>` as a trait bound to the functions."""
1202+
1203+
# ASYNC
1204+
1205+
[[exercises]]
1206+
name = "async1"
1207+
dir = "24_async"
1208+
test = false
1209+
hint = """
1210+
Asynchronous runtimes like tokio can only spawn tasks that are defined as async
1211+
functions, not regular ones. Add the "async" keyword before the "fn" keyword of
1212+
the functions "tim", "carl" and "nick".
1213+
1214+
An async task can wait for another one to complete by "awaiting" it. Add
1215+
".await" after the three "task_name" variables in the "block_on" call."""

solutions/24_async/async1.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Tim has to complete a few chores today, before he's allowed to play soccer
2+
// with his friends. His friends decide to help him. Working together, they
3+
// finish the chores earlier and have more time left to play soccer.
4+
//
5+
// Let's simulate this using asynchronous programming. Each boy is represented
6+
// as an asynchronous task, which can be executed concurrently (they can be
7+
// working at the same time).
8+
9+
use std::sync::atomic::{AtomicU8, Ordering};
10+
11+
fn do_chores() {
12+
// Async tasks need to be executed by a "runtime", which is not provided by
13+
// Rust's standard library. We use the popular "tokio" runtime here.
14+
let rt = tokio::runtime::Builder::new_current_thread()
15+
.build()
16+
.unwrap();
17+
18+
let task_tim = rt.spawn(tim());
19+
let task_carl = rt.spawn(carl());
20+
let task_nick = rt.spawn(nick());
21+
22+
// Block the runtime on a task that waits for all boys to finish the chores.
23+
// TODO: "await" all three tasks to fix the compiler errors.
24+
rt.block_on(async {
25+
task_tim.await.unwrap();
26+
task_carl.await.unwrap();
27+
task_nick.await.unwrap();
28+
});
29+
30+
assert_eq!(
31+
CHORES_DONE.load(Ordering::SeqCst),
32+
3,
33+
"Did you (a)wait for all the boys to finish the chores?"
34+
);
35+
println!("Ready to play soccer!");
36+
}
37+
38+
/// Used by "mom" to check that all chores are done before Tim plays soccer :-)
39+
static CHORES_DONE: AtomicU8 = AtomicU8::new(0);
40+
41+
async fn tim() {
42+
println!("Cleaning my room...");
43+
CHORES_DONE.fetch_add(1, Ordering::SeqCst);
44+
}
45+
46+
async fn carl() {
47+
println!("Washing the dishes...");
48+
CHORES_DONE.fetch_add(1, Ordering::SeqCst);
49+
}
50+
51+
async fn nick() {
52+
println!("Mowing the lawn...");
53+
CHORES_DONE.fetch_add(1, Ordering::SeqCst);
54+
}
55+
56+
fn main() {
57+
do_chores();
58+
}

0 commit comments

Comments
 (0)