update codes

This commit is contained in:
breayhing 2024-07-11 21:27:09 +08:00
parent a8bcac9c6f
commit 2c7f64424c
11 changed files with 129 additions and 424 deletions

240
Cargo.lock generated
View File

@ -2,21 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.8.11"
@ -120,21 +105,6 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "backtrace"
version = "0.3.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -158,12 +128,6 @@ dependencies = [
"serde",
]
[[package]]
name = "bytes"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
[[package]]
name = "cassowary"
version = "0.3.0"
@ -179,12 +143,6 @@ dependencies = [
"rustversion",
]
[[package]]
name = "cc"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -344,101 +302,6 @@ dependencies = [
"libc",
]
[[package]]
name = "futures"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-executor"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
[[package]]
name = "futures-macro"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]]
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-util"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "gimli"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]]
name = "hashbrown"
version = "0.14.5"
@ -455,12 +318,6 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "indexmap"
version = "2.2.6"
@ -569,15 +426,6 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "miniz_oxide"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.11"
@ -634,25 +482,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "object"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@ -698,18 +527,6 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "predicates"
version = "3.1.0"
@ -826,12 +643,6 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustlings"
version = "6.1.0"
@ -840,7 +651,6 @@ dependencies = [
"assert_cmd",
"clap",
"crossterm",
"futures",
"hashbrown",
"notify-debouncer-mini",
"os_pipe",
@ -849,7 +659,6 @@ dependencies = [
"rustlings-macros",
"serde",
"serde_json",
"tokio",
"toml_edit",
]
@ -959,31 +768,12 @@ dependencies = [
"libc",
]
[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "socket2"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "stability"
version = "0.2.1"
@ -1045,36 +835,6 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
[[package]]
name = "tokio"
version = "1.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
"num_cpus",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.48.0",
]
[[package]]
name = "tokio-macros"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml_datetime"
version = "0.6.6"

View File

@ -48,9 +48,6 @@ include = [
[dependencies]
anyhow = "1.0.86"
tokio = { version = "1.0", features = ["full"] }
futures = "0.3"
clap = { version = "4.5.9", features = ["derive"] }
crossterm = "0.27.0"
hashbrown = "0.14.5"

View File

@ -192,8 +192,6 @@ bin = [
{ name = "async1_sol", path = "../solutions/24_async/async1.rs" },
{ name = "async2", path = "../exercises/24_async/async2.rs" },
{ name = "async2_sol", path = "../solutions/24_async/async2.rs" },
{ name = "async3", path = "../exercises/24_async/async3.rs" },
{ name = "async3_sol", path = "../solutions/24_async/async3.rs" },
]
[package]

View File

@ -18,4 +18,3 @@ Navigate the complexities of error handling in async code. Understand how errors
- [Learn more about async programming in Rust](https://doc.rust-lang.org/book/ch16-00-concurrency.html)
- [Deep dive into handling concurrency](https://doc.rust-lang.org/book/ch16-02-message-passing.html)
- [Advanced async patterns](https://tokio.rs/tokio/tutorial)

View File

@ -1,30 +1,22 @@
// 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 async_std::task;
use std::time::{Duration, Instant};
use tokio::time::{sleep, Duration};
async fn perform_task(id: usize) -> u128 {
async fn run_async_task(id: usize) -> u128 {
let start = Instant::now();
// Simulate async work using sleep
tokio::time::sleep(Duration::from_millis(250)).await;
// TODO: Replace the synchronous sleep with an asynchronous sleep.
task::sleep(Duration::from_millis(250)).await;
println!("Task {id} done");
start.elapsed().as_millis()
}
async fn main_async() {
let mut handles = Vec::new();
async fn main() {
let mut tasks = Vec::new();
for i in 0..10 {
let handle = perform_task(i);
handles.push(handle);
// TODO: Push new asynchronous tasks into the vector.
}
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.
}
// TODO: Wait for all tasks to complete and collect their results.
if results.len() != 10 {
panic!("Oh no! Some task isn't done yet!");
@ -36,6 +28,7 @@ async fn main_async() {
}
}
// Main function that starts the async main function using `task::block_on`.
fn main() {
block_on(main_async());
task::block_on(main());
}

View File

@ -1,31 +1,60 @@
// 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 async_std::task;
use std::time::{Duration, Instant};
use std::fmt;
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
#[derive(Debug)]
enum TaskError {
Timeout,
Other(String),
}
// TODO: Convert this function to async version
async fn calculate_value_asynchronously() -> i32 {
impl fmt::Display for TaskError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
TaskError::Timeout => write!(f, "Task timed out"),
TaskError::Other(ref err) => write!(f, "Other error: {}", err),
}
}
}
async fn main_async() {
println!("Calling synchronous function:");
let sync_result = calculate_value_synchronously();
println!("Result from synchronous function: {}", sync_result);
// TODO: Define an asynchronous function that may return an error.
async fn run_async_task(id: usize) -> Result<u128, TaskError> {
let start = Instant::now();
// Simulate a possible failure
if id == 5 {
// Simulate a timeout error
task::sleep(Duration::from_millis(100)).await;
return Err(TaskError::Timeout);
} else if id == 8 {
// Simulate another type of error
return Err(TaskError::Other("Unexpected error".to_string()));
}
// TODO: Call the async function here and print its result
// Normal operation with async sleep
task::sleep(Duration::from_millis(250)).await;
println!("Task {id} done");
Ok(start.elapsed().as_millis())
}
async fn main() {
let mut tasks = Vec::new();
// TODO: Create and store asynchronous tasks in the `tasks` vector.
for i in 0..10 {
tasks.push(run_async_task(i)); }
// TODO: Wait for all tasks to complete and collect their results, handling errors appropriately.
// Process results
for (i, result) in results.into_iter().enumerate() {
match result {
Ok(duration) => println!("Task {i} took {duration}ms"),
Err(e) => println!("Task {i} failed with error: {}", e),
}
}
}
// Main function that starts the async main function using `task::block_on`.
fn main() {
block_on(main_async());
task::block_on(main());
}

View File

@ -1,40 +0,0 @@
// 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

@ -1209,16 +1209,10 @@ Add `AsRef<str>` or `AsMut<u32>` as a trait bound to the functions."""
name = "async1"
dir = "24_async"
hint = """
Use `.await` to collect the results of all tasks into the `results` vector."""
Push new asynchronous tasks into the vector."""
[[exercises]]
name = "async2"
dir = "24_async"
hint = """
Synchronous version of a function that simulates a long-running operation"""
[[exercises]]
name = "async3"
dir = "24_async"
hint = """
Consider using match or Result combinators like `map_err` or `and_then`."""
Wait for all tasks to complete and collect their results, handling errors appropriately."""

View File

@ -1,30 +1,25 @@
// 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.
// Importing necessary modules from async-std to handle asynchronous tasks.
use async_std::task;
use std::time::{Duration, Instant};
use tokio::time::{sleep, Duration};
async fn perform_task(id: usize) -> u128 {
async fn run_async_task(id: usize) -> u128 {
let start = Instant::now();
// Simulate async work using sleep
tokio::time::sleep(Duration::from_millis(250)).await;
// Simulate work by sleeping, but now this is asynchronous sleep.
task::sleep(Duration::from_millis(250)).await;
println!("Task {id} done");
start.elapsed().as_millis()
}
async fn main_async() {
let mut handles = Vec::new();
async fn main() {
let mut tasks = Vec::new();
// Create asynchronous tasks
for i in 0..10 {
let handle = perform_task(i);
handles.push(handle);
tasks.push(run_async_task(i));
}
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);
}
// Wait for all tasks to complete and collect their results.
let results = futures::future::join_all(tasks).await;
if results.len() != 10 {
panic!("Oh no! Some task isn't done yet!");
@ -36,7 +31,7 @@ async fn main_async() {
}
}
#[tokio::main]
async fn main() {
main_async().await;
}
// Main function now starts the async main function using `task::block_on`.
fn main() {
task::block_on(main());
}

View File

@ -1,37 +1,60 @@
// 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 async_std::task;
use std::time::{Duration, Instant};
use std::fmt;
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
// 自定义错误类型
#[derive(Debug)]
enum TaskError {
Timeout,
Other(String),
}
// 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
impl fmt::Display for TaskError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
TaskError::Timeout => write!(f, "Task timed out"),
TaskError::Other(ref err) => write!(f, "Other error: {}", err),
}
}
}
async fn main_async() {
println!("Calling synchronous function:");
let sync_result = calculate_value_synchronously();
println!("Result from synchronous function: {}", sync_result);
async fn run_async_task(id: usize) -> Result<u128, TaskError> {
let start = Instant::now();
// Simulate a possible failure
if id == 5 {
// Simulate a timeout error
task::sleep(Duration::from_millis(100)).await;
return Err(TaskError::Timeout);
} else if id == 8 {
// Simulate another type of error
return Err(TaskError::Other("Unexpected error".to_string()));
}
println!("Calling asynchronous function:");
let async_result = calculate_value_asynchronously().await;
println!("Result from asynchronous function: {}", async_result);
// Normal operation with async sleep
task::sleep(Duration::from_millis(250)).await;
println!("Task {id} done");
Ok(start.elapsed().as_millis())
}
async fn main() {
let mut tasks = Vec::new();
for i in 0..10 {
tasks.push(run_async_task(i));
}
let results: Vec<Result<u128, TaskError>> = futures::future::join_all(tasks).await;
// Process results
for (i, result) in results.into_iter().enumerate() {
match result {
Ok(duration) => println!("Task {i} took {duration}ms"),
Err(e) => println!("Task {i} failed with error: {}", e),
}
}
}
// Main function that starts the async main function using `task::block_on`.
fn main() {
block_on(main_async());
task::block_on(main());
}

View File

@ -1,43 +0,0 @@
// 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());
}