如何在Rust中实现类似Python的切片步长赋值?(素数筛迁移)
替代Python素数筛切片赋值的Rust高性能实现
Python中的full_array[test:max:index] = False本质是依赖底层向量化的批量内存操作(通常是numpy或CPython的优化实现),所以能高效处理超大数组。Rust要达到同级性能,无需回避循环——关键是让编译器生成接近底层的优化代码,或利用专门的bit数组库提升缓存效率。
方案1:纯标准库unsafe实现(无外部依赖)
Rust的Vec<bool>本身是位压缩存储(8个布尔值占1字节),比Python的字节级布尔列表更省内存,缓存命中率更高。通过unsafe直接操作指针,编译器会自动将循环优化为接近C的高效代码:
unsafe fn set_step_to_false(arr: &mut [bool], start: usize, step: usize) { let arr_len = arr.len(); if start >= arr_len { return; } let mut ptr = arr.as_mut_ptr().add(start); let mut current_idx = start; while current_idx < arr_len { *ptr = false; current_idx += step; ptr = ptr.add(step); } } // 素数筛示例用法 fn sieve(max: usize) -> Vec<bool> { let mut sieve = vec![true; max + 1]; sieve[0] = false; sieve[1] = false; let sqrt_max = (max as f64).sqrt() as usize; for i in 2..=sqrt_max { if sieve[i] { // 从i*i开始,步长i标记非素数 unsafe { set_step_to_false(&mut sieve, i * i, i); } } } sieve }
这里的unsafe代码无风险(已提前做边界检查),编译器会将循环展开并向量化,性能可对标Python的numpy实现。
方案2:用bitvec库(更简洁且性能更优)
bitvec是Rust生态中专门处理位数组的库,内置了批量步长操作的优化实现,内存效率和执行速度都比标准库Vec<bool>更出色:
use bitvec::prelude::*; fn sieve(max: usize) -> BitVec { let mut sieve = bitvec![true; max + 1]; sieve.set(0, false); sieve.set(1, false); let sqrt_max = (max as f64).sqrt() as usize; for i in 2..=sqrt_max { if sieve[i] { // 直接通过切片步长批量设置为false sieve[i*i..=max].step_by(i).set_all(false); } } sieve }
bitvec的step_by和set_all方法底层用SIMD指令和内存块操作优化,处理100亿级别的素数筛时,内存仅占用约125MB,速度会超过Python的实现。
为什么普通循环慢?
如果用普通的for i in (test..max).step_by(index) { full_array[i] = false; },对于Vec<bool>,编译器优化程度可能略低;如果用Vec<u8>存储布尔值,会占用8倍内存,导致缓存命中率下降,性能骤降。而上面的两种方案都解决了这些问题。
内容的提问来源于stack exchange,提问作者Wes
相关产品推荐
相关产品推荐

