diff --git a/book/listings/main_event_loop/8/main.rs b/book/listings/main_event_loop/8/main.rs
index eb00996eb0ee..1a42beb78c4c 100644
--- a/book/listings/main_event_loop/8/main.rs
+++ b/book/listings/main_event_loop/8/main.rs
@@ -43,7 +43,7 @@ fn build_ui(app: &Application) {
main_context.spawn_local(clone!(@weak button => async move {
while let Ok(response) = receiver.recv().await {
if let Ok(response) = response {
- println!("Status {}", response.status());
+ println!("Status: {}", response.status());
} else {
println!("Could not make a `GET` request.");
}
diff --git a/book/listings/main_event_loop/9/main.rs b/book/listings/main_event_loop/9/main.rs
index 79f28cf055b6..291f48aeffa2 100644
--- a/book/listings/main_event_loop/9/main.rs
+++ b/book/listings/main_event_loop/9/main.rs
@@ -47,7 +47,7 @@ fn build_ui(app: &Application) {
main_context.spawn_local(clone!(@weak button => async move {
while let Ok(response) = receiver.recv().await {
if let Ok(response) = response {
- println!("Status {}", response.status());
+ println!("Status: {}", response.status());
} else {
println!("Could not make a `GET` request.");
}
diff --git a/book/src/main_event_loop.md b/book/src/main_event_loop.md
index 00f466b03c89..e8a108f29b33 100644
--- a/book/src/main_event_loop.md
+++ b/book/src/main_event_loop.md
@@ -65,7 +65,7 @@ However, we don't want to block the main loop while waiting for a message to rec
That is the whole point of the exercise after all!
We solve that problem by waiting for messages to receive in an [`async`](https://rust-lang.github.io/async-book/) block.
-We spawn that `async` block on the glib main loop with [`spawn_local`](https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/struct.MainContext.html#method.spawn_local) (from other threads than the main thread [`spawn`](https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/struct.MainContext.html#method.spawn) has to be used).
+We spawn that `async` block on the `glib` main loop with [`spawn_local`](https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/struct.MainContext.html#method.spawn_local) (from other threads than the main thread [`spawn`](https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/struct.MainContext.html#method.spawn) has to be used).
Filename: listings/main_event_loop/3/main.rs
@@ -176,9 +176,9 @@ help: within `gtk4::Button`, the trait `Sync` is not implemented for `NonNull
+## Tokio
+
+[`tokio`](https://docs.rs/tokio/latest/tokio/) is Rust's most popular asynchronous platform.
+Therefore, many high-quality crates are part of its ecosystem.
+The web client [`reqwest`](https://docs.rs/reqwest/latest/reqwest/) belongs to this group.
+Let's add it by executing the following command
```
cargo add reqwest@0.11 --features rustls-tls --no-default-features
```
+As soon as the button is pressed, we want to send a `GET` request to [www.gtk-rs.org](https://www.gtk-rs.org).
+The response should then be sent to the main thread via a channel.
+
Filename: listings/main_event_loop/8/main.rs
```rust
{{#rustdoc_include ../listings/main_event_loop/8/main.rs:callback}}
```
+This compiles fine and even seems to run.
+However, nothing happens when we press the button.
+Inspecting the console gives the following error message:
+
+```
+thread 'main' panicked at
+'there is no reactor running, must be called from the context of a Tokio 1.x runtime'
+```
+
+At the time of writing, `reqwest` doesn't document this requirement.
+Unfortunately, that is also the case for other libraries depending on `tokio`.
+Let's bite the bullet and add `tokio`:
+
```
cargo add tokio@1 --features rt-multi-thread
```
+Since we already run the `glib` main loop on our main thread, we don't want to run the `tokio` runtime there.
+Let's bind it to a static variable and initialize it lazily.
Filename: listings/main_event_loop/9/main.rs
@@ -241,19 +265,44 @@ Filename: listings/main_event_loop/9/main.rs
```rust
{{#rustdoc_include ../listings/main_event_loop/9/main.rs:callback}}
```
+If we now press the button, we should find the following message in our console:
+
+```
+Status: 200 OK
+```
+
+We will not need `tokio` or `reqwest` in the following chapters, so let's remove it again by executing:
+
+```
+cargo remove reqwest tokio
+```
+
+How to find out whether you can spawn an `async` task on the `glib` main loop?
+You should be able to do that when the called functions come from libraries that either:
+- come from the `glib` ecosystem,
+- depend on `async-std`/`smol`, or
+- have cargo features that let them depend on `async-std`/`smol` instead of `tokio`.
+
+
+## Conclusion
-So when should you spawn an `async` block and when should you spawn a thread?
+You don't want to block the main thread long enough that it is noticable by the user.
+But when should you spawn an `async` task, and when should you spawn a task in a separate thread?
+Let's go again through the different scenarios.
-# TODO
+If you spend your time calculating rather than waiting for a web response, your task is [CPU-bound](https://en.wikipedia.org/wiki/CPU-bound).
+That means you have to run your task in a separate thread and send results back via a channel.
-- computation bound -> threads + channels
-- IO:
- - if you have glib/smol/async-std functions -> spawn on main loop (+ maybe channels)
- - if tokio lib is better -> spawn on tokio + channels
- - if those are not good options -> threads + channels
+If your task is [IO bound](https://en.wikipedia.org/wiki/I/O_bound), it depends on the crates at your disposal
+Functions from crates using `glib`/`smol`/`async-std` can be spawned on the main loop.
+This typically leads to straightforward code, which can often avoid synchronization via channels.
+If the best crate for the job relies on `tokio`, you will have to spawn it with the tokio runtime and send the results via channels.