面试题答案
一键面试- 共享资源处理:
- 使用
Arc
(原子引用计数):Arc
用于在多个线程间共享数据。例如,假设有一个需要在多个网络请求处理任务间共享的配置结构体Config
:
- 使用
use std::sync::Arc;
struct Config {
// 配置字段
server_addr: String,
}
let config = Arc::new(Config {
server_addr: "127.0.0.1:8080".to_string(),
});
- 这样,不同的任务可以通过`Arc`来持有对`config`的引用,从而共享该配置数据。
- 结合
Mutex
或RwLock
:- 当共享资源需要可变访问时,结合
Mutex
(互斥锁)。例如,假设有一个共享的计数器Counter
:
- 当共享资源需要可变访问时,结合
use std::sync::{Arc, Mutex};
struct Counter {
value: u32,
}
let counter = Arc::new(Mutex::new(Counter { value: 0 }));
// 在一个任务中增加计数器
let mut count = counter.lock().unwrap();
count.value += 1;
- 如果共享资源读取频繁,写入较少,可以使用`RwLock`(读写锁),允许多个任务同时读取,但只允许一个任务写入。
2. 避免数据竞争:
- Rust所有权系统:
- Rust的所有权系统从根本上防止数据竞争。每个值在任何时刻有且只有一个所有者。在并发环境中,当将数据传递给不同的任务时,所有权会发生转移。例如:
let data = "some data".to_string();
tokio::spawn(async move {
// data的所有权转移到这个任务中
println!("Task got data: {}", data);
});
Send
和Sync
trait:Send
:实现了Send
trait的类型可以安全地在线程间传递。例如,大多数基本类型(如i32
、String
等)都实现了Send
。自定义类型如果其所有字段都实现了Send
,那么该自定义类型也自动实现Send
。Sync
:实现了Sync
trait的类型可以安全地在多个线程间共享。同样,基本类型大多实现了Sync
,自定义类型若其所有字段都实现Sync
,则该自定义类型也实现Sync
。
- 利用Rust类型系统和并发原语实现安全高效的并发网络编程:
tokio
的mpsc
通道:- 用于在不同任务间安全地传递数据。例如,一个任务生成数据,另一个任务消费数据:
use tokio::sync::mpsc;
let (tx, mut rx) = mpsc::channel(100);
tokio::spawn(async move {
// 发送数据
tx.send("data to send".to_string()).await.unwrap();
});
tokio::spawn(async move {
// 接收数据
if let Some(data) = rx.recv().await {
println!("Received: {}", data);
}
});
Mutex
和Condvar
:Mutex
用于保护共享资源,Condvar
(条件变量)用于线程间的同步。例如,一个任务等待某个条件满足,另一个任务改变条件并通知等待的任务:
use std::sync::{Arc, Condvar, Mutex};
let data = Arc::new((Mutex::new(false), Condvar::new()));
let data_clone = data.clone();
tokio::spawn(async move {
let (lock, cvar) = &*data;
let mut ready = lock.lock().unwrap();
while!*ready {
ready = cvar.wait(ready).unwrap();
}
println!("Condition is met");
});
tokio::spawn(async move {
let (lock, cvar) = &*data_clone;
let mut ready = lock.lock().unwrap();
*ready = true;
cvar.notify_one();
});
tokio
的Semaphore
:- 用于限制并发度。例如,限制同时处理的网络请求数量:
use tokio::sync::Semaphore;
let semaphore = Arc::new(Semaphore::new(10));
let permit = semaphore.acquire().await.unwrap();
// 处理网络请求
drop(permit);