面试题答案
一键面试1. 实现代码
use std::sync::{Arc, Mutex};
use rayon::prelude::*;
// 判断一个复数是否属于曼德博集
fn is_in_mandelbrot(c: complex::Complex<f64>, max_iter: u32) -> bool {
let mut z = complex::Complex::new(0.0, 0.0);
for _ in 0..max_iter {
if z.norm_sqr() > 4.0 {
return false;
}
z = z * z + c;
}
true
}
fn mandelbrot_in_rectangle(
x_min: f64,
x_max: f64,
y_min: f64,
y_max: f64,
width: u32,
height: u32,
max_iter: u32,
) -> Vec<Vec<bool>> {
let mut result = vec![vec![false; width as usize]; height as usize];
let result_arc = Arc::new(Mutex::new(result));
(0..height).into_par_iter().for_each(|j| {
let y = y_min + (y_max - y_min) * (j as f64 / (height - 1) as f64);
let local_result = result_arc.lock().unwrap();
for i in 0..width {
let x = x_min + (x_max - x_min) * (i as f64 / (width - 1) as f64);
let c = complex::Complex::new(x, y);
local_result[j as usize][i as usize] = is_in_mandelbrot(c, max_iter);
}
});
*result_arc.lock().unwrap()
}
2. 同步机制说明
Arc
:- 作用:
Arc
(原子引用计数)用于在多个线程间共享数据。在上述代码中,result_arc
是一个Arc<Mutex<Vec<Vec<bool>>>>
,通过Arc
使得多个线程可以持有对result
数据结构的引用。 - 选择原因:因为
Vec<Vec<bool>>
是一个较大的数据结构,将其在每个线程中进行拷贝是不现实的,Arc
提供了一种在多个线程间高效共享数据的方式,并且它是线程安全的。
- 作用:
Mutex
:- 作用:
Mutex
(互斥锁)用于保护共享数据,确保同一时间只有一个线程可以访问被保护的数据。在代码中,result_arc
内部的Mutex
保证了在对result
进行读写操作时,不会出现数据竞争。 - 选择原因:由于多个线程可能同时尝试修改
result
中的数据,Mutex
提供了一种简单有效的同步机制,通过锁的方式来避免数据竞争,保证数据的一致性。
- 作用:
3. 关于rayon
库
在上述代码中,使用了rayon
库的into_par_iter
方法来并行处理任务。rayon
库提供了一个线程池,能够自动管理线程的创建和销毁,并且它可以根据系统的CPU核心数来动态调整并行度,提高计算效率。
4. 注意事项
- 上述代码中的
complex
类型假设是来自num-complex
库,使用前需在Cargo.toml
文件中添加依赖:
[dependencies]
num-complex = "0.4"
rayon = "1.5"
- 实际应用中,可以根据具体需求调整
max_iter
、矩形区域的边界值以及图像的分辨率(width
和height
)。