exercises + threads
This commit is contained in:
1645
Cargo.lock
generated
1645
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,8 @@ edition = "2021"
|
||||
default-run = "rust-by-example"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.9.2"
|
||||
reqwest = "0.12.22"
|
||||
# clap = "2.27.1" # from crates.io
|
||||
# rand = { git = "https://github.com/rust-lang-nursery/rand" } # from online repo
|
||||
# bar = { path = "../bar" } # from a path in the local filesystem
|
||||
|
||||
@@ -1 +1 @@
|
||||
# Rust by example
|
||||
# [Rust by example](https://doc.rust-lang.org/stable/rust-by-example/)
|
||||
|
||||
66
src/exercises/hard_difficulty.rs
Normal file
66
src/exercises/hard_difficulty.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
*
|
||||
Exercise: Implement a Multithreaded Web Crawler
|
||||
|
||||
#### Objective:
|
||||
Create a simple multithreaded web crawler in Rust that can visit a set of web pages concurrently and extract all the links from those pages.
|
||||
|
||||
#### Requirements:
|
||||
1. **Concurrent Fetching:** The crawler should utilize multiple threads to fetch web pages to improve performance.
|
||||
2. **Link Extraction:** For each page visited by the crawler, extract all the hyperlinks (`<a href="...">`) present on the page.
|
||||
3. **Avoid Cycles:** Ensure the crawler doesn't visit the same page more than once.
|
||||
4. **Limit Depth:** Allow the user to specify the maximum depth for crawling (i.e., the maximum number of links to follow from the initial set of given URLs).
|
||||
5. **Graceful Shutdown:** Allow the crawler to be stopped gracefully upon receiving a user interrupt (like pressing Ctrl+C).
|
||||
|
||||
#### Steps to Implement:
|
||||
1. **Set Up the Project:**
|
||||
- Create a new Rust project using Cargo.
|
||||
|
||||
2. **Implement URL Fetching:**
|
||||
- Use `reqwest` or a similar library to fetch the contents of a web page.
|
||||
- Handle networking errors gracefully.
|
||||
|
||||
3. **Extract Links:**
|
||||
- Use the `scraper` crate or implement your own HTML parsing logic to extract links from the fetched HTML content.
|
||||
|
||||
4. **Multithreading:**
|
||||
- Utilize Rust's `std::thread` or the `tokio` runtime to spawn threads that can concurrently fetch and process web pages.
|
||||
|
||||
5. **Avoid Revisits:**
|
||||
- Maintain a `HashSet` or similar structure to keep track of visited URLs to prevent revisiting the same page.
|
||||
|
||||
6. **Depth Control:**
|
||||
- Use a data structure (like a queue) to manage the list of URLs to visit, and keep track of the current depth level for each URL.
|
||||
|
||||
7. **Graceful Shutdown:**
|
||||
- Implement signal handling to catch user interrupts and terminate the crawling process gracefully.
|
||||
|
||||
8. **Testing:**
|
||||
- Write tests to ensure the crawler functions as expected, including edge cases like broken links, non-responsive pages, etc.
|
||||
|
||||
#### Hints:
|
||||
- Consider using Rust's ownership model to manage shared state across threads safely.
|
||||
- Make use of concurrency primitives like `Arc` and `Mutex` to safely share data between threads.
|
||||
- Efficiently manage the queue of URLs to visit, making sure to handle potential deadlocks and race conditions.
|
||||
|
||||
This exercise will test the candidate's ability to work with network requests, concurrency, and data structures in Rust, while also evaluating their understanding of graceful error handling and software design.
|
||||
*/
|
||||
|
||||
// #[derive(Debug)]
|
||||
// struct HyperLink<'a> {
|
||||
// href: &'a str,
|
||||
// label: &'a str,
|
||||
// }
|
||||
|
||||
// struct PageData<'a> {
|
||||
// links: Vec<HyperLink<'a>>,
|
||||
// url: &'a str,
|
||||
// }
|
||||
|
||||
// pub fn web_crawler(url_list: Vec<&str>) -> Vec<PageData> {}
|
||||
|
||||
// fn get_page_links(url: &str) -> PageData {
|
||||
// PageData { links: (), url }
|
||||
// }
|
||||
|
||||
// fn get_page_body(url: &str) -> &str {}
|
||||
@@ -1,3 +1,48 @@
|
||||
/*
|
||||
* Count squares
|
||||
*/
|
||||
pub fn count_squares(matrix: &Vec<Vec<bool>>) -> usize {
|
||||
let mut square_count: usize = 0;
|
||||
|
||||
for j in 0..matrix.len() {
|
||||
for i in 0..matrix[0].len() {
|
||||
if matrix[i][j] == true {}
|
||||
}
|
||||
}
|
||||
|
||||
square_count
|
||||
}
|
||||
|
||||
fn does_matrix_square_at(matrix: &Vec<Vec<bool>>) -> bool {}
|
||||
|
||||
/*
|
||||
* Mirror number
|
||||
*/
|
||||
pub fn mirror_number(mut value: u32) -> u32 {
|
||||
const BASE: u32 = 10;
|
||||
|
||||
let mut mirror: u32 = 0;
|
||||
let size = value.to_string().len();
|
||||
|
||||
for index in 1..=size {
|
||||
let last = value % BASE;
|
||||
value = value / BASE;
|
||||
mirror += last * BASE.pow(size as u32 - index as u32);
|
||||
}
|
||||
|
||||
mirror
|
||||
}
|
||||
|
||||
pub fn mirror_number_lazy(value: u32) -> u32 {
|
||||
value
|
||||
.to_string()
|
||||
.chars()
|
||||
.rev()
|
||||
.collect::<String>()
|
||||
.parse::<u32>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn longest_palindrome(value: &str) -> String {
|
||||
let mut lp: String = "0".to_string();
|
||||
let input_size = value.len() - 1;
|
||||
@@ -21,6 +66,9 @@ pub fn longest_palindrome(value: &str) -> String {
|
||||
lp
|
||||
}
|
||||
|
||||
/*
|
||||
* Quick sort
|
||||
*/
|
||||
pub fn quick_sort<T>(list: Vec<T>) -> Vec<T>
|
||||
where
|
||||
T: PartialOrd + Copy,
|
||||
|
||||
@@ -1,8 +1,46 @@
|
||||
use std::time::Instant;
|
||||
|
||||
mod easy_difficulty;
|
||||
mod hard_difficulty;
|
||||
mod medium_difficulty;
|
||||
|
||||
pub fn run_hard() {
|
||||
println!();
|
||||
}
|
||||
|
||||
pub fn run_medium() {
|
||||
println!("{}", medium_difficulty::longest_palindrome("asdffdas"));
|
||||
println!(
|
||||
"Longest palindrome of 'asdffdas' is {}",
|
||||
medium_difficulty::longest_palindrome("asdffdas")
|
||||
);
|
||||
|
||||
let to_mirror = 12345u32;
|
||||
|
||||
let begin = Instant::now();
|
||||
println!(
|
||||
"The mirror of {} is {} and took {:?}",
|
||||
to_mirror,
|
||||
medium_difficulty::mirror_number(to_mirror),
|
||||
begin.elapsed()
|
||||
);
|
||||
|
||||
let begin = Instant::now();
|
||||
println!(
|
||||
"(lazy) The mirror of {} is {} and took {:?}",
|
||||
to_mirror,
|
||||
medium_difficulty::mirror_number_lazy(to_mirror),
|
||||
begin.elapsed()
|
||||
);
|
||||
|
||||
let boolean_matrix = vec![
|
||||
vec![true, false, true, true],
|
||||
vec![false, false, true, true],
|
||||
];
|
||||
println!(
|
||||
"The matrix:\n{:?}\nhas {} squares inside",
|
||||
boolean_matrix,
|
||||
medium_difficulty::count_squares(&boolean_matrix)
|
||||
);
|
||||
}
|
||||
|
||||
pub fn run_easy() {
|
||||
|
||||
10
src/main.rs
10
src/main.rs
@@ -5,8 +5,7 @@
|
||||
// : /// Doc comment: generate library docs for the following item
|
||||
// : //! Doc comment
|
||||
|
||||
mod macros;
|
||||
use macros::macros_rule;
|
||||
mod threads;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "./test/basic_test.rs"]
|
||||
@@ -22,10 +21,13 @@ fn main() {
|
||||
// controlflow::control_flow_module();
|
||||
// traits::traits_exercise();
|
||||
// str_types::str_types_module();
|
||||
// exercises::run_easy();
|
||||
// my_lib::public_function();
|
||||
// functions::functions_module();
|
||||
// concepts::box_basics();
|
||||
// operators::operators_module();
|
||||
macros_rule();
|
||||
// macros_rule();
|
||||
|
||||
// exercises::run_easy();
|
||||
// exercises::run_medium();
|
||||
threads::threads_module();
|
||||
}
|
||||
|
||||
68
src/threads.rs
Normal file
68
src/threads.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
use std::{thread, time::Instant};
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
const NTHREADS: u32 = 6;
|
||||
|
||||
fn generate_number_block(size: usize) -> String {
|
||||
let mut block = String::new();
|
||||
for _ in 0..size {
|
||||
block.push_str(&rand::rng().random_range(0..9).to_string());
|
||||
}
|
||||
block
|
||||
}
|
||||
|
||||
pub fn threads_module() {
|
||||
let number_block = generate_number_block(999999);
|
||||
|
||||
let time = Instant::now();
|
||||
let result_base = sum_of_block(&number_block);
|
||||
let elapsed_base = time.elapsed();
|
||||
println!("Functional took {}", elapsed_base.as_micros());
|
||||
|
||||
let time = Instant::now();
|
||||
let result_parallel = sum_of_block_parallel(&number_block, 10);
|
||||
let elapsed_parallel = time.elapsed();
|
||||
println!("Parallel took {}", elapsed_parallel.as_micros());
|
||||
|
||||
if result_base == result_parallel {
|
||||
println!(
|
||||
"The results are the same ({}) and the time difference is {}",
|
||||
result_base,
|
||||
elapsed_parallel.as_micros() - elapsed_base.as_micros()
|
||||
)
|
||||
} else {
|
||||
println!("One is wrong...");
|
||||
}
|
||||
}
|
||||
|
||||
fn sum_of_block_parallel(digits: &str, nthreads: usize) -> u32 {
|
||||
let digits = digits.split_at(digits.len() / 2);
|
||||
3
|
||||
}
|
||||
|
||||
fn sum_of_block(digits: &str) -> u32 {
|
||||
digits
|
||||
.chars()
|
||||
.into_iter()
|
||||
.map(|character| character.to_digit(10).unwrap())
|
||||
.sum::<u32>()
|
||||
}
|
||||
|
||||
fn basic_thread_wait() {
|
||||
let mut thread_list = vec![];
|
||||
for i in 0..NTHREADS {
|
||||
thread_list.push(thread::spawn(move || {
|
||||
println!("this is the thread {}", i);
|
||||
return 1;
|
||||
}));
|
||||
}
|
||||
|
||||
for th in thread_list {
|
||||
let result = th.join();
|
||||
match result {
|
||||
Ok(r) => println!("Thread finished! {:?}", r),
|
||||
Err(e) => println!("Thread error {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user