From f7f25279517fdbb73208e84fe53cb52649e3bf09 Mon Sep 17 00:00:00 2001 From: breayhing <1519981563@qq.com> Date: Thu, 11 Jul 2024 20:18:34 +0800 Subject: [PATCH] add exercises of async --- exercises/24_async/README.md | 6 ----- exercises/24_async/async1.rs | 41 ++++++++++++++++++++++++++++++++++ exercises/24_async/async2.rs | 31 ++++++++++++++++++++++++++ exercises/24_async/async3.rs | 40 +++++++++++++++++++++++++++++++++ solutions/24_async/async1.rs | 41 ++++++++++++++++++++++++++++++++++ solutions/24_async/async2.rs | 37 +++++++++++++++++++++++++++++++ solutions/24_async/async3.rs | 43 ++++++++++++++++++++++++++++++++++++ 7 files changed, 233 insertions(+), 6 deletions(-) create mode 100644 exercises/24_async/async1.rs create mode 100644 exercises/24_async/async2.rs create mode 100644 exercises/24_async/async3.rs create mode 100644 solutions/24_async/async1.rs create mode 100644 solutions/24_async/async2.rs create mode 100644 solutions/24_async/async3.rs diff --git a/exercises/24_async/README.md b/exercises/24_async/README.md index a7373a7a..bca92a05 100644 --- a/exercises/24_async/README.md +++ b/exercises/24_async/README.md @@ -8,12 +8,6 @@ Discover the basics of asynchronous programming by writing your first async func ## Using Async and Await Convert a traditional synchronous function to use async/await syntax. This exercise helps illustrate the benefits and usage of Rust’s async constructs. -## Understanding Task Execution -Learn about executing multiple tasks concurrently without blocking. This exercise focuses on how Rust handles async task execution under the hood. - -## Shared State in Async Code -Tackle the challenges of managing shared state in an asynchronous context. Use synchronization tools like Mutexes to safely manage state across concurrent tasks. - ## Error Handling in Async Navigate the complexities of error handling in async code. Understand how errors propagate differently in async workflows and how to handle them effectively. diff --git a/exercises/24_async/async1.rs b/exercises/24_async/async1.rs new file mode 100644 index 00000000..c4d59d8a --- /dev/null +++ b/exercises/24_async/async1.rs @@ -0,0 +1,41 @@ +// This program creates multiple asynchronous tasks that each simulate a long-running operation +// using `async` and `await`. Each task will return how much time it took to complete. +// The program should wait until all the tasks have finished and should collect their return values into a vector. + +use std::time::{Duration, Instant}; +use futures::executor::block_on; // For simplicity in an educational context, to block on async code + +async fn perform_task(id: usize) -> u128 { + let start = Instant::now(); + // Simulate async work using sleep + tokio::time::sleep(Duration::from_millis(250)).await; + println!("Task {id} done"); + start.elapsed().as_millis() +} + +async fn main_async() { + let mut handles = Vec::new(); + for i in 0..10 { + let handle = perform_task(i); + handles.push(handle); + } + + let mut results = Vec::new(); + for handle in handles { + // TODO: Use `.await` to collect the results of all tasks into the `results` vector. + // Remember to handle each async task using the appropriate syntax for awaiting. + } + + if results.len() != 10 { + panic!("Oh no! Some task isn't done yet!"); + } + + println!(); + for (i, result) in results.into_iter().enumerate() { + println!("Task {i} took {result}ms"); + } +} + +fn main() { + block_on(main_async()); +} diff --git a/exercises/24_async/async2.rs b/exercises/24_async/async2.rs new file mode 100644 index 00000000..dbc32c41 --- /dev/null +++ b/exercises/24_async/async2.rs @@ -0,0 +1,31 @@ +// This program demonstrates the transformation of a synchronous function into an asynchronous one. +// The original function performs a time-consuming operation, which we'll simulate with a sleep. +// You need to convert this function to use async/await syntax and understand how it improves the responsiveness of the application. + +use std::time::Duration; +use futures::executor::block_on; // This is for running the async main function in this educational context. + +// Synchronous version of a function that simulates a long-running operation +fn calculate_value_synchronously() -> i32 { + println!("Starting synchronous calculation..."); + std::thread::sleep(Duration::from_secs(2)); // Simulating a long-running task + println!("Synchronous calculation done."); + 42 // returns a computed value +} + +// TODO: Convert this function to async version +async fn calculate_value_asynchronously() -> i32 { + +} + +async fn main_async() { + println!("Calling synchronous function:"); + let sync_result = calculate_value_synchronously(); + println!("Result from synchronous function: {}", sync_result); + + // TODO: Call the async function here and print its result +} + +fn main() { + block_on(main_async()); +} diff --git a/exercises/24_async/async3.rs b/exercises/24_async/async3.rs new file mode 100644 index 00000000..64507971 --- /dev/null +++ b/exercises/24_async/async3.rs @@ -0,0 +1,40 @@ +// This program demonstrates error handling in asynchronous Rust code. We will simulate a function that can fail, +// and you will handle the error appropriately in an asynchronous context. + +use std::time::Duration; +use futures::executor::block_on; // For running the async main function in this educational context. +use tokio; // We use tokio for the async functionality. +use anyhow::{Result, anyhow}; // To simplify error handling + +// Asynchronous function that might fail +async fn might_fail(id: u32) -> Result { + if id % 2 == 0 { + tokio::time::sleep(Duration::from_millis(500)).await; + Ok(id) + } else { + tokio::time::sleep(Duration::from_millis(500)).await; + Err(anyhow!("Failed on odd id")) + } +} + +async fn main_async() { + let ids = [1, 2, 3, 4, 5]; + let mut results = Vec::new(); + + for id in ids { + // TODO: Handle the potential error here using appropriate async error handling methods. + // Consider using match or Result combinators like `map_err` or `and_then`. + } + + // Display results + for result in results { + match result { + Ok(num) => println!("Processed number: {}", num), + Err(e) => println!("Error occurred: {}", e), + } + } +} + +fn main() { + block_on(main_async()); +} diff --git a/solutions/24_async/async1.rs b/solutions/24_async/async1.rs new file mode 100644 index 00000000..d60ed185 --- /dev/null +++ b/solutions/24_async/async1.rs @@ -0,0 +1,41 @@ +// This program creates multiple asynchronous tasks that each simulate a long-running operation +// using `async` and `await`, and each task will return how much time it took to complete. +// The program should wait until all the tasks have finished and should collect their return values into a vector. + +use std::time::{Duration, Instant}; +use futures::executor::block_on; // This will allow us to block on async code for simplicity in an educational context + +async fn perform_task(id: usize) -> u128 { + let start = Instant::now(); + // Simulate async work using sleep + tokio::time::sleep(Duration::from_millis(250)).await; + println!("Task {id} done"); + start.elapsed().as_millis() +} + +async fn main_async() { + let mut handles = Vec::new(); + for i in 0..10 { + let handle = perform_task(i); + handles.push(handle); + } + + let mut results = Vec::new(); + for handle in handles { + // Use `.await` to collect the results of all tasks into the `results` vector. + results.push(handle.await); + } + + if results.len() != 10 { + panic!("Oh no! Some task isn't done yet!"); + } + + println!(); + for (i, result) in results.into_iter().enumerate() { + println!("Task {i} took {result}ms"); + } +} + +fn main() { + block_on(main_async()); +} diff --git a/solutions/24_async/async2.rs b/solutions/24_async/async2.rs new file mode 100644 index 00000000..4167f452 --- /dev/null +++ b/solutions/24_async/async2.rs @@ -0,0 +1,37 @@ +// This program demonstrates the transformation of a synchronous function into an asynchronous one. +// The original function performs a time-consuming operation, which we'll simulate with a sleep. +// You need to convert this function to use async/await syntax and understand how it improves the responsiveness of the application. + +use std::time::Duration; +use futures::executor::block_on; // This is for running the async main function in this educational context. +use tokio; // We use tokio for the async sleep functionality. + +// Synchronous version of a function that simulates a long-running operation +fn calculate_value_synchronously() -> i32 { + println!("Starting synchronous calculation..."); + std::thread::sleep(Duration::from_secs(2)); // Simulating a long-running task + println!("Synchronous calculation done."); + 42 // returns a computed value +} + +// Converted to async version +async fn calculate_value_asynchronously() -> i32 { + println!("Starting asynchronous calculation..."); + tokio::time::sleep(Duration::from_secs(2)).await; // Using Tokio's async sleep + println!("Asynchronous calculation done."); + 42 // returns a computed value +} + +async fn main_async() { + println!("Calling synchronous function:"); + let sync_result = calculate_value_synchronously(); + println!("Result from synchronous function: {}", sync_result); + + println!("Calling asynchronous function:"); + let async_result = calculate_value_asynchronously().await; + println!("Result from asynchronous function: {}", async_result); +} + +fn main() { + block_on(main_async()); +} diff --git a/solutions/24_async/async3.rs b/solutions/24_async/async3.rs new file mode 100644 index 00000000..1a133b54 --- /dev/null +++ b/solutions/24_async/async3.rs @@ -0,0 +1,43 @@ +// This program demonstrates error handling in asynchronous Rust code. We simulate a function that can fail, +// and handle the error appropriately in an asynchronous context. + +use std::time::Duration; +use futures::executor::block_on; // For running the async main function in this educational context. +use tokio; // We use tokio for the async functionality. +use anyhow::{Result, anyhow}; // To simplify error handling + +// Asynchronous function that might fail +async fn might_fail(id: u32) -> Result { + if id % 2 == 0 { + tokio::time::sleep(Duration::from_millis(500)).await; + Ok(id) + } else { + tokio::time::sleep(Duration::from_millis(500)).await; + Err(anyhow!("Failed on odd id")) + } +} + +async fn main_async() { + let ids = [1, 2, 3, 4, 5]; + let mut results = Vec::new(); + + for id in ids { + let result = might_fail(id).await; + match result { + Ok(num) => results.push(Ok(num)), + Err(e) => results.push(Err(e)), + } + } + + // Display results + for result in results { + match result { + Ok(num) => println!("Processed number: {}", num), + Err(e) => println!("Error occurred: {}", e), + } + } +} + +fn main() { + block_on(main_async()); +}