diff --git a/async-book/ci/dictionary.txt b/async-book/ci/dictionary.txt index aeab728..5c0fe90 100644 --- a/async-book/ci/dictionary.txt +++ b/async-book/ci/dictionary.txt @@ -9,6 +9,7 @@ AsyncRead AsyncWrite AwaitingFutOne AwaitingFutTwo +cancelling combinator combinators compat @@ -37,6 +38,7 @@ interprocess IoBlocker IOCP IoObject +JoinHandle kqueue localhost LocalExecutor diff --git a/async-book/examples/06_04_spawning/Cargo.toml b/async-book/examples/06_04_spawning/Cargo.toml new file mode 100644 index 0000000..e70d1b4 --- /dev/null +++ b/async-book/examples/06_04_spawning/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "example_06_04_spawning" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +futures = "0.3" + +[dependencies.async-std] +version = "1.12.0" +features = ["attributes"] \ No newline at end of file diff --git a/async-book/examples/06_04_spawning/src/lib.rs b/async-book/examples/06_04_spawning/src/lib.rs new file mode 100644 index 0000000..e6f7c50 --- /dev/null +++ b/async-book/examples/06_04_spawning/src/lib.rs @@ -0,0 +1,46 @@ +#![cfg(test)] +#![allow(dead_code)] + +// ANCHOR: example +use async_std::{task, net::TcpListener, net::TcpStream}; +use futures::AsyncWriteExt; + +async fn process_request(stream: &mut TcpStream) -> Result<(), std::io::Error>{ + stream.write_all(b"HTTP/1.1 200 OK\r\n\r\n").await?; + stream.write_all(b"Hello World").await?; + Ok(()) +} + +async fn main() { + let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap(); + loop { + // Accept a new connection + let (mut stream, _) = listener.accept().await.unwrap(); + // Now process this request without blocking the main loop + task::spawn(async move {process_request(&mut stream).await}); + } +} +// ANCHOR_END: example +use std::time::Duration; +async fn my_task(time: Duration) { + println!("Hello from my_task with time {:?}", time); + task::sleep(time).await; + println!("Goodbye from my_task with time {:?}", time); +} +// ANCHOR: join_all +use futures::future::join_all; +async fn task_spawner(){ + let tasks = vec![ + task::spawn(my_task(Duration::from_secs(1))), + task::spawn(my_task(Duration::from_secs(2))), + task::spawn(my_task(Duration::from_secs(3))), + ]; + // If we do not await these tasks and the function finishes, they will be dropped + join_all(tasks).await; +} +// ANCHOR_END: join_all + +#[test] +fn run_task_spawner() { + futures::executor::block_on(task_spawner()); +} \ No newline at end of file diff --git a/async-book/examples/Cargo.toml b/async-book/examples/Cargo.toml index 2c3cf87..99566a7 100644 --- a/async-book/examples/Cargo.toml +++ b/async-book/examples/Cargo.toml @@ -10,6 +10,7 @@ members = [ "05_02_iteration_and_concurrency", "06_02_join", "06_03_select", + "06_04_spawning", "07_05_recursion", "09_01_sync_tcp_server", "09_02_async_tcp_server", diff --git a/async-book/src/06_multiple_futures/04_spawning.md b/async-book/src/06_multiple_futures/04_spawning.md new file mode 100644 index 0000000..8177f0e --- /dev/null +++ b/async-book/src/06_multiple_futures/04_spawning.md @@ -0,0 +1,24 @@ +# `Spawning` + +Spawning allows you to run a new asynchronous task in the background. This allows us to continue executing other code +while it runs. + +Say we have a web server that wants to accept connections without blocking the main thread. +To achieve this, we can use the `async_std::task::spawn` function to create and run a new task that handles the +connections. This function takes a future and returns a `JoinHandle`, which can be used to wait for the result of the +task once it's completed. + +```rust,edition2018 +{{#include ../../examples/06_04_spawning/src/lib.rs:example}} +``` + +The `JoinHandle` returned by `spawn` implements the `Future` trait, so we can `.await` it to get the result of the task. +This will block the current task until the spawned task completes. If the task is not awaited, your program will +continue executing without waiting for the task, cancelling it if the function is completed before the task is finished. + +```rust,edition2018 +{{#include ../../examples/06_04_spawning/src/lib.rs:join_all}} +``` + +To communicate between the main task and the spawned task, we can use channels +provided by the async runtime used. \ No newline at end of file diff --git a/async-book/src/12_appendix/01_translations.md b/async-book/src/12_appendix/01_translations.md index 8202757..d6fa47a 100644 --- a/async-book/src/12_appendix/01_translations.md +++ b/async-book/src/12_appendix/01_translations.md @@ -4,3 +4,4 @@ For resources in languages other than English. - [Русский](https://doc.rust-lang.ru/async-book/) - [Français](https://jimskapt.github.io/async-book-fr/) +- [فارسی](https://rouzbehsbz.github.io/rust-async-book/) diff --git a/async-book/src/SUMMARY.md b/async-book/src/SUMMARY.md index a089ceb..122fe1e 100644 --- a/async-book/src/SUMMARY.md +++ b/async-book/src/SUMMARY.md @@ -16,7 +16,7 @@ - [Executing Multiple Futures at a Time](06_multiple_futures/01_chapter.md) - [`join!`](06_multiple_futures/02_join.md) - [`select!`](06_multiple_futures/03_select.md) - - [TODO: Spawning]() + - [Spawning](06_multiple_futures/04_spawning.md) - [TODO: Cancellation and Timeouts]() - [TODO: `FuturesUnordered`]() - [Workarounds to Know and Love](07_workarounds/01_chapter.md)