在 Rust 中用零值初始化结构向量
Initialize a vector of struct with zero values in Rust
- 我有一个 结构向量 并想用 全零 .
初始化它
struct MyStruct {
v1: u32,
v2: u64,
}
type MyVector = Vec<MyStruct>;
- 因为向量的大小已知,我可以指定容量。
我的第一种方法如下,
impl Default for MyStruct {
fn default() -> Self {
Self {
v1: 0,
v2: 0,
}
}
}
fn init_my_vec() {
let size = 1000;
let mut my_vec: MyVector = Vec::with_capacity(size);
(0..size).for_each(|_| my_vec.push(MyStruct::default()))
}
- 据我所知,向量初始化为 0 比使用迭代器要快。像这样,
let usize_vec: Vec<usize> = vec![0; 1000];
// is faster than
let mut usize_vec: Vec<usize> = Vec::with_capacity(1000);
for i in 0..1000 {
usize_vec.push(0);
}
问题
- 我对矢量初始化速度的看法是否正确?由于用0填充是特殊指令,使用迭代器比使用宏慢。
- 有没有什么方法可以安全又快速的初始化0值struct的vector
- 或者我应该使用 不安全 代码,比如制作空字节并将其转换为向量?
速度测量大约 Question 1
const VEC_SIZE: usize = 10_000;
fn init_with_iter() -> u128 {
let start = Instant::now();
let mut usize_vec: Vec<usize> = Vec::with_capacity(VEC_SIZE);
for i in 0..VEC_SIZE {
usize_vec.push(0);
}
start.elapsed().as_micros()
}
fn init_with_macro() -> u128 {
let start = Instant::now();
let _: Vec<usize> = vec![0; VEC_SIZE];
start.elapsed().as_micros()
}
生成向量 10,000 次的平均时间是
- 使用 iter(
init_with_iter
):514.6805 毫秒
- 使用宏(
init_with_macro
):2.0361 毫秒
在我的机器上
测速约Question 3
我认为使用不安全函数 mem::zeroed
比任何其他函数都快一点
const VEC_SIZE: usize = 10_000;
fn init_with_iter() -> u128 {
let start = Instant::now();
let mut my_vec: MyVector = Vec::with_capacity(VEC_SIZE);
for _ in 0..VEC_SIZE {
my_vec.push(MyStruct::default());
}
start.elapsed().as_micros()
}
fn init_with_macro() -> u128 {
let start = Instant::now();
let _: MyVector = vec![MyStruct::default(); VEC_SIZE];
start.elapsed().as_micros()
}
fn init_with_zeroed() -> u128 {
let start = Instant::now();
let _: MyVector = unsafe { vec![std::mem::zeroed(); VEC_SIZE] };
start.elapsed().as_micros()
}
生成向量 1,000 次的平均时间是
- 使用 iter(
init_with_iter
):575.572 毫秒。
- 使用宏(
init_with_macro
):486.958 毫秒
- 使用不安全函数(
init_with_zeroed
):468.885 毫秒
在我的机器上
这是您的三种方法的 criterion 基准:
use criterion::{black_box, criterion_group, criterion_main, Criterion};
criterion_group!(
benches,
init_structs_with_iter,
init_structs_with_macro,
init_structs_with_unsafe
);
criterion_main!(benches);
const N_ITEMS: usize = 1000;
#[allow(unused)]
#[derive(Debug, Clone)]
struct MyStruct {
v1: u32,
v2: u64,
}
impl Default for MyStruct {
fn default() -> Self {
Self { v1: 0, v2: 0 }
}
}
fn init_structs_with_iter(c: &mut Criterion) {
c.bench_function("structs: with_iter", |b| {
b.iter(|| {
let mut my_vec = Vec::with_capacity(N_ITEMS);
(0..my_vec.capacity()).for_each(|_| my_vec.push(MyStruct::default()));
black_box(my_vec);
})
});
}
fn init_structs_with_macro(c: &mut Criterion) {
c.bench_function("structs: with_macro", |b| {
b.iter(|| {
let my_vec = vec![MyStruct::default(); N_ITEMS];
black_box(my_vec);
})
});
}
fn init_structs_with_unsafe(c: &mut Criterion) {
c.bench_function("structs: with_unsafe", |b| {
b.iter(|| {
let my_vec: Vec<MyStruct> = vec![unsafe { std::mem::zeroed() }; N_ITEMS];
black_box(my_vec);
})
});
}
结果:
structs: with_iter time: [1.3857 us 1.3960 us 1.4073 us]
structs: with_macro time: [563.30 ns 565.30 ns 567.32 ns]
structs: with_unsafe time: [568.84 ns 570.09 ns 571.49 ns]
vec![]
宏似乎是最快的(也是最简洁易读的)。
如您所见,时间以 纳秒 为单位测量,因此虽然迭代器版本慢 2-3 倍,但在实践中并不重要。优化结构的零初始化是您可以做的最不重要的事情 - 您最多可以节省 1 微秒 ;)
PS:这些时间包括内存分配和释放时间
- 我有一个 结构向量 并想用 全零 . 初始化它
struct MyStruct {
v1: u32,
v2: u64,
}
type MyVector = Vec<MyStruct>;
- 因为向量的大小已知,我可以指定容量。 我的第一种方法如下,
impl Default for MyStruct {
fn default() -> Self {
Self {
v1: 0,
v2: 0,
}
}
}
fn init_my_vec() {
let size = 1000;
let mut my_vec: MyVector = Vec::with_capacity(size);
(0..size).for_each(|_| my_vec.push(MyStruct::default()))
}
- 据我所知,向量初始化为 0 比使用迭代器要快。像这样,
let usize_vec: Vec<usize> = vec![0; 1000];
// is faster than
let mut usize_vec: Vec<usize> = Vec::with_capacity(1000);
for i in 0..1000 {
usize_vec.push(0);
}
问题
- 我对矢量初始化速度的看法是否正确?由于用0填充是特殊指令,使用迭代器比使用宏慢。
- 有没有什么方法可以安全又快速的初始化0值struct的vector
- 或者我应该使用 不安全 代码,比如制作空字节并将其转换为向量?
速度测量大约 Question 1
const VEC_SIZE: usize = 10_000;
fn init_with_iter() -> u128 {
let start = Instant::now();
let mut usize_vec: Vec<usize> = Vec::with_capacity(VEC_SIZE);
for i in 0..VEC_SIZE {
usize_vec.push(0);
}
start.elapsed().as_micros()
}
fn init_with_macro() -> u128 {
let start = Instant::now();
let _: Vec<usize> = vec![0; VEC_SIZE];
start.elapsed().as_micros()
}
生成向量 10,000 次的平均时间是
- 使用 iter(
init_with_iter
):514.6805 毫秒 - 使用宏(
init_with_macro
):2.0361 毫秒
在我的机器上
测速约Question 3
我认为使用不安全函数 mem::zeroed
比任何其他函数都快一点
const VEC_SIZE: usize = 10_000;
fn init_with_iter() -> u128 {
let start = Instant::now();
let mut my_vec: MyVector = Vec::with_capacity(VEC_SIZE);
for _ in 0..VEC_SIZE {
my_vec.push(MyStruct::default());
}
start.elapsed().as_micros()
}
fn init_with_macro() -> u128 {
let start = Instant::now();
let _: MyVector = vec![MyStruct::default(); VEC_SIZE];
start.elapsed().as_micros()
}
fn init_with_zeroed() -> u128 {
let start = Instant::now();
let _: MyVector = unsafe { vec![std::mem::zeroed(); VEC_SIZE] };
start.elapsed().as_micros()
}
生成向量 1,000 次的平均时间是
- 使用 iter(
init_with_iter
):575.572 毫秒。 - 使用宏(
init_with_macro
):486.958 毫秒 - 使用不安全函数(
init_with_zeroed
):468.885 毫秒
在我的机器上
这是您的三种方法的 criterion 基准:
use criterion::{black_box, criterion_group, criterion_main, Criterion};
criterion_group!(
benches,
init_structs_with_iter,
init_structs_with_macro,
init_structs_with_unsafe
);
criterion_main!(benches);
const N_ITEMS: usize = 1000;
#[allow(unused)]
#[derive(Debug, Clone)]
struct MyStruct {
v1: u32,
v2: u64,
}
impl Default for MyStruct {
fn default() -> Self {
Self { v1: 0, v2: 0 }
}
}
fn init_structs_with_iter(c: &mut Criterion) {
c.bench_function("structs: with_iter", |b| {
b.iter(|| {
let mut my_vec = Vec::with_capacity(N_ITEMS);
(0..my_vec.capacity()).for_each(|_| my_vec.push(MyStruct::default()));
black_box(my_vec);
})
});
}
fn init_structs_with_macro(c: &mut Criterion) {
c.bench_function("structs: with_macro", |b| {
b.iter(|| {
let my_vec = vec![MyStruct::default(); N_ITEMS];
black_box(my_vec);
})
});
}
fn init_structs_with_unsafe(c: &mut Criterion) {
c.bench_function("structs: with_unsafe", |b| {
b.iter(|| {
let my_vec: Vec<MyStruct> = vec![unsafe { std::mem::zeroed() }; N_ITEMS];
black_box(my_vec);
})
});
}
结果:
structs: with_iter time: [1.3857 us 1.3960 us 1.4073 us]
structs: with_macro time: [563.30 ns 565.30 ns 567.32 ns]
structs: with_unsafe time: [568.84 ns 570.09 ns 571.49 ns]
vec![]
宏似乎是最快的(也是最简洁易读的)。
如您所见,时间以 纳秒 为单位测量,因此虽然迭代器版本慢 2-3 倍,但在实践中并不重要。优化结构的零初始化是您可以做的最不重要的事情 - 您最多可以节省 1 微秒 ;)
PS:这些时间包括内存分配和释放时间