-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Introduce an alternative day-4-afternoon: async #492
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Async Rust | ||
|
||
"Async" is a concurrency model where multiple tasks are executed concurrently by | ||
executing each task until it would block, then switching to another task that is | ||
ready to make progress. The model scales to higher concurrency than threads | ||
because the per-task overhead is typically very low and operating systems | ||
provide means of efficiently selecting tasks that can make progress. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: It sounds like there is inherent OS support for async/await. Perhaps reword to something like "the async/await implementation relies on OS primitive to efficiently select the next tasks to run". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I addressed this, but I'm happy for more editing :) |
||
|
||
djmitche marked this conversation as resolved.
Show resolved
Hide resolved
|
||
## Comparisons | ||
|
||
* Python has a similar model in its `asyncio`. However, its `Future` type is | ||
callback-based, and not polled. Async Python programs require a "loop", | ||
similar to an executor in Rust. | ||
|
||
* JavaScript's `Promise` is similar, but again callback-based. The language | ||
runtime implements the event loop, so many of the details of Promise | ||
resolution are hidden. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# `async`/`await` | ||
|
||
At a high level, async Rust code looks very much like "normal" sequential code: | ||
|
||
```rust,editable | ||
use tokio::time; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to skip using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Using |
||
|
||
async fn count_to(i: i32) { | ||
for i in 1..10 { | ||
println!("Count in task: {i}!"); | ||
time::sleep(time::Duration::from_millis(5)).await; | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
tokio::spawn(count_to(10)); | ||
|
||
for i in 1..5 { | ||
println!("Main task: {i}"); | ||
time::sleep(time::Duration::from_millis(5)).await; | ||
} | ||
} | ||
``` | ||
|
||
<details> | ||
|
||
Key points: | ||
|
||
* Tokio is one of several async runtimes available for Rust. | ||
|
||
* The function is decorated with the "async" keyword to indicate that it is async. The | ||
`tokio::main` macro invocation is a convenience to wrap the `main` function as a task. | ||
|
||
* The `spawn` function creates a new, concurrent "task", just like spawning a thread. | ||
|
||
* Whenever a task would block, we add an `.await` which returns control to the runtime until the | ||
blocking operation is ready to proceed. | ||
|
||
Further exploration: | ||
|
||
* Why does `count_to` not (usually) get to 10? This is an example of async cancellation. | ||
`tokio::spawn` returns a handle which can be awaited to wait until it finishes. | ||
|
||
* Try `count_to(10).await` instead of spawning. | ||
|
||
* Try importing `tokio::join` and using it to join multiple handles. | ||
|
||
Note that the Rust playground does not allow network connections, so examples like making HTTP | ||
requests are not possible. | ||
|
||
</details> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Async Blocks | ||
|
||
Similar to closures, a snippet of async code can be included inline in another | ||
function with an async block: | ||
|
||
```rust, editable | ||
use tokio::{time, task}; | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let mut joinset = task::JoinSet::new(); | ||
|
||
for i in 1..5 { | ||
joinset.spawn(async move { | ||
println!("task {i} starting"); | ||
time::sleep(time::Duration::from_millis(i)).await; | ||
println!("task {i} done"); | ||
format!("hello from task {i}") | ||
}); | ||
} | ||
|
||
while let Some(res) = joinset.join_next().await { | ||
let greeting = res.unwrap(); | ||
println!("task joined with result: {greeting}"); | ||
} | ||
} | ||
|
||
<details> | ||
|
||
An async block is similar to a closure, but does not take any arguments. | ||
|
||
Its return value is a Future, which is described on the next slide. | ||
|
||
</details> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Exercises | ||
|
||
TBD |
Uh oh!
There was an error while loading. Please reload this page.