当我运行此代码时:
#[derive(Copy, Clone)]
pub struct Element {
pub key: u64,
}
pub fn test1(u: usize) {
let now = std::time::SystemTime::now();
let tt = vec![Element { key: 0 }; u];
for _ in 0..10000000 as u64 {
if tt[155].key == 893472348628 {}
}
match now.elapsed() {
Ok(elapsed) => {
println!(
"With struct, size of vec={}: Time elapsed: {}.{} seconds",
u,
elapsed.as_secs(),
elapsed.subsec_nanos()
);
}
Err(e) => {
println!("Error: {:?}", e);
panic!();
}
}
}
pub fn test2(u: usize) {
let now = std::time::SystemTime::now();
let tt = vec![0u64; u];
for _ in 0..10000000 as u64 {
if tt[155] == 893472348628 {}
}
match now.elapsed() {
Ok(elapsed) => {
println!(
"With u64, size of vec={}: Time elapsed: {}.{} seconds",
u,
elapsed.as_secs(),
elapsed.subsec_nanos()
);
}
Err(e) => {
println!("Error: {:?}", e);
panic!();
}
}
}
fn main() {
test1(100000);
test1(100000000);
test2(100000);
test2(100000000);
}
我得到这些结果:
With struct, size of vec=100000: Time elapsed: 1.268881822 seconds
With struct, size of vec=100000000: Time elapsed: 12.470818140 seconds
With u64, size of vec=100000: Time elapsed: 1.171180429 seconds
With u64, size of vec=100000000: Time elapsed: 1.230393828 seconds
我没有看到任何理由为什么第二个函数调用应该比第一个函数调用慢10倍。我确实在调试模式下编译它,因为发布模式忽略了这些行:
if tt[155].key == 893472348628 {}
我有一台带有8GB内存的64位Linux机器,也许它与它有关?
它不是访问需要时间的元素,而是初始化向量。的确,通过你的例子我得到:
With struct, size of vec=100000: Time elapsed: 0.594704815 seconds
With struct, size of vec=100000000: Time elapsed: 5.789152687 seconds
With u64, size of vec=100000: Time elapsed: 0.584137362 seconds
With u64, size of vec=100000000: Time elapsed: 0.586343084 seconds
如果我在now
之后初始化tt
我得到以下内容:
With struct, size of vec=100000: Time elapsed: 0.589499628 seconds
With struct, size of vec=100000000: Time elapsed: 0.583244899 seconds
With u64, size of vec=100000: Time elapsed: 0.584675666 seconds
With u64, size of vec=100000000: Time elapsed: 0.583518382 seconds
初始化向量需要线性时间,因为每个元素都需要初始化为0
(或Element { key: 0 }
)。
至于为什么0
比Element { key: 0 }
更快,让我们来看看vec!
是如何工作的。 We can see it just calls vec::from_elem
,反过来just calls <T as SpecFromElem>::from_elem
。这个特质是什么?好吧,它的默认实现基本上看起来像:
let mut v = Vec::with_capacity(n);
v.extend_with(n, ExtendElement(elem));
但也有一个bunch of special cases,包括一个0u64
!这个使用RawVec::with_capacity_zeroed(n)
。毫无疑问,这种特殊情况是速度的来源。