MST

星途 面试题库

面试题:Rust多线程环境下ID分配原子策略的优化

假设你在一个多线程的Rust程序中实现ID分配的原子策略,已经使用了`AtomicUsize`来保证ID分配的原子性,但发现性能瓶颈在每次获取新ID时的全局锁竞争上。描述至少两种优化方案来提升性能,比如从缓存、批量分配等角度考虑,并写出关键代码示例。
33.1万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
  1. 缓存局部ID
    • 原理:每个线程维护自己的局部ID缓存,减少对全局AtomicUsize的访问频率。只有当局部缓存耗尽时,才从全局ID池中获取一批新的ID。
    • 关键代码示例
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};

// 全局ID分配器
static GLOBAL_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);

// 线程本地缓存
thread_local! {
    static LOCAL_ID_CACHE: Mutex<Vec<usize>> = Mutex::new(Vec::new());
}

fn get_id() -> usize {
    LOCAL_ID_CACHE.with(|cache| {
        let mut cache = cache.lock().unwrap();
        if cache.is_empty() {
            // 从全局ID池中获取一批新的ID
            let batch_size = 100;
            let start_id = GLOBAL_ID_COUNTER.fetch_add(batch_size, Ordering::SeqCst);
            for i in 0..batch_size {
                cache.push(start_id + i);
            }
        }
        cache.pop().unwrap()
    })
}
  1. 批量分配ID
    • 原理:每次请求ID时,不是单个分配,而是一次分配一批ID给调用者。这样减少了获取锁的次数。
    • 关键代码示例
use std::sync::atomic::{AtomicUsize, Ordering};

// 全局ID分配器
static GLOBAL_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);

fn get_ids(count: usize) -> Vec<usize> {
    let start_id = GLOBAL_ID_COUNTER.fetch_add(count, Ordering::SeqCst);
    (0..count).map(|i| start_id + i).collect()
}
  1. 使用无锁数据结构(如AtomicCell
    • 原理:在某些场景下,AtomicCell 提供了更细粒度的控制,可能减少锁竞争。它允许在不使用锁的情况下对内部值进行原子操作。
    • 关键代码示例
use std::sync::atomic::{AtomicCell, Ordering};

// 全局ID分配器
static GLOBAL_ID_COUNTER: AtomicCell<usize> = AtomicCell::new(0);

fn get_id() -> usize {
    let current_id = GLOBAL_ID_COUNTER.load(Ordering::SeqCst);
    GLOBAL_ID_COUNTER.store(current_id + 1, Ordering::SeqCst);
    current_id
}