add exercises of async

This commit is contained in:
breayhing 2024-07-11 20:18:34 +08:00
parent ac9443f516
commit f7f2527951
7 changed files with 233 additions and 6 deletions

View File

@ -8,12 +8,6 @@ Discover the basics of asynchronous programming by writing your first async func
## Using Async and Await ## Using Async and Await
Convert a traditional synchronous function to use async/await syntax. This exercise helps illustrate the benefits and usage of Rusts async constructs. Convert a traditional synchronous function to use async/await syntax. This exercise helps illustrate the benefits and usage of Rusts 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 ## 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. Navigate the complexities of error handling in async code. Understand how errors propagate differently in async workflows and how to handle them effectively.

View File

@ -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());
}

View File

@ -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());
}

View File

@ -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<u32> {
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());
}

View File

@ -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());
}

View File

@ -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());
}

View File

@ -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<u32> {
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());
}