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"
|
default-run = "rust-by-example"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
rand = "0.9.2"
|
||||||
|
reqwest = "0.12.22"
|
||||||
# clap = "2.27.1" # from crates.io
|
# clap = "2.27.1" # from crates.io
|
||||||
# rand = { git = "https://github.com/rust-lang-nursery/rand" } # from online repo
|
# rand = { git = "https://github.com/rust-lang-nursery/rand" } # from online repo
|
||||||
# bar = { path = "../bar" } # from a path in the local filesystem
|
# 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 {
|
pub fn longest_palindrome(value: &str) -> String {
|
||||||
let mut lp: String = "0".to_string();
|
let mut lp: String = "0".to_string();
|
||||||
let input_size = value.len() - 1;
|
let input_size = value.len() - 1;
|
||||||
@@ -21,6 +66,9 @@ pub fn longest_palindrome(value: &str) -> String {
|
|||||||
lp
|
lp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Quick sort
|
||||||
|
*/
|
||||||
pub fn quick_sort<T>(list: Vec<T>) -> Vec<T>
|
pub fn quick_sort<T>(list: Vec<T>) -> Vec<T>
|
||||||
where
|
where
|
||||||
T: PartialOrd + Copy,
|
T: PartialOrd + Copy,
|
||||||
|
|||||||
@@ -1,8 +1,46 @@
|
|||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
mod easy_difficulty;
|
mod easy_difficulty;
|
||||||
|
mod hard_difficulty;
|
||||||
mod medium_difficulty;
|
mod medium_difficulty;
|
||||||
|
|
||||||
|
pub fn run_hard() {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_medium() {
|
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() {
|
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: generate library docs for the following item
|
||||||
// : //! Doc comment
|
// : //! Doc comment
|
||||||
|
|
||||||
mod macros;
|
mod threads;
|
||||||
use macros::macros_rule;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "./test/basic_test.rs"]
|
#[path = "./test/basic_test.rs"]
|
||||||
@@ -22,10 +21,13 @@ fn main() {
|
|||||||
// controlflow::control_flow_module();
|
// controlflow::control_flow_module();
|
||||||
// traits::traits_exercise();
|
// traits::traits_exercise();
|
||||||
// str_types::str_types_module();
|
// str_types::str_types_module();
|
||||||
// exercises::run_easy();
|
|
||||||
// my_lib::public_function();
|
// my_lib::public_function();
|
||||||
// functions::functions_module();
|
// functions::functions_module();
|
||||||
// concepts::box_basics();
|
// concepts::box_basics();
|
||||||
// operators::operators_module();
|
// 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