From d143528e07d1b6bb06dc4c1ac2f44c8267e5f7d4 Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Sun, 16 Apr 2023 19:20:24 -0400 Subject: [PATCH] Minor fix-ups to the async section. (#566) These address some comments in #496. --- src/async/control-flow/select.md | 6 ++++-- src/async/pitfalls/async-traits.md | 13 +++++++------ src/async/pitfalls/pin.md | 4 +++- src/async/tasks.md | 4 ++-- src/exercises/day-4/async.md | 3 --- 5 files changed, 16 insertions(+), 14 deletions(-) delete mode 100644 src/exercises/day-4/async.md diff --git a/src/async/control-flow/select.md b/src/async/control-flow/select.md index 7e416ea1..62d5ac4e 100644 --- a/src/async/control-flow/select.md +++ b/src/async/control-flow/select.md @@ -69,7 +69,9 @@ async fn main() { * Try adding a deadline to the race, demonstrating selecting different sorts of futures. -* Note that `select!` consumes the futures it is given, and is easiest to use - when every execution of `select!` creates new futures. +* Note that `select!` moves the values it is given. It is easiest to use + when every execution of `select!` creates new futures. An alternative is to + pass `&mut future` instead of the future itself, but this can lead to + issues, further discussed in the pinning slide. diff --git a/src/async/pitfalls/async-traits.md b/src/async/pitfalls/async-traits.md index 93e9ef8a..f643b196 100644 --- a/src/async/pitfalls/async-traits.md +++ b/src/async/pitfalls/async-traits.md @@ -48,13 +48,14 @@ async fn main() {
-* The difficulty with `async trait` is in that the resulting `Future` does not - have a size known at compile time, because the size of the `Future` depends - on the implementation. - * `async_trait` is easy to use, but note that it's using heap allocations to - achieve this, and solve the unknow size problem above. This heap allocation - has performance overhead. + achieve this. This heap allocation has performance overhead. + +* The challenges in language support for `async trait` are deep Rust and + probably not worth describing in-depth. Niko Matsakis did a good job of + explaining them in [this + post](https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/) + if you are interested in digging deeper. * Try creating a new sleeper struct that will sleep for a random amount of time and adding it to the Vec. diff --git a/src/async/pitfalls/pin.md b/src/async/pitfalls/pin.md index 455e19ee..a6b92112 100644 --- a/src/async/pitfalls/pin.md +++ b/src/async/pitfalls/pin.md @@ -103,8 +103,10 @@ async fn main() { iteration (a fused future would help with this). Update to reset `timeout_fut` every time it expires. -* Box allocates on the heap. In some cases, `tokio::pin!` is also an option, but +* Box allocates on the heap. In some cases, `std::pin::pin!` (only recently + stabilized, with older code often using `tokio::pin!`) is also an option, but that is difficult to use for a future that is reassigned. + * Another alternative is to not use `pin` at all but spawn another task that will send to a `oneshot` channel every 100ms.
diff --git a/src/async/tasks.md b/src/async/tasks.md index e00499f8..6aebfa07 100644 --- a/src/async/tasks.md +++ b/src/async/tasks.md @@ -1,9 +1,9 @@ # Tasks -Runtimes have the concept of a "Task", similar to a thread but much +Runtimes have the concept of a "task", similar to a thread but much less resource-intensive. -A Task has a single top-level Future which the executor polls to make progress. +A task has a single top-level future which the executor polls to make progress. That future may have one or more nested futures that its `poll` method polls, corresponding loosely to a call stack. Concurrency within a task is possible by polling multiple child futures, such as racing a timer and an I/O operation. diff --git a/src/exercises/day-4/async.md b/src/exercises/day-4/async.md deleted file mode 100644 index 14047188..00000000 --- a/src/exercises/day-4/async.md +++ /dev/null @@ -1,3 +0,0 @@ -# Exercises - -TBD