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