2017-12-31 150 views
0

私はこのコードを実行すると:なぜデバッグモードで構造体の大きなベクトルの要素にアクセスするのが、より小さなものにアクセスするよりも遅いのですか?

#[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 

私は2番目の関数呼び出しが最初のものよりも10倍遅くなるべき理由何らかの理由が表示されません。

if tt[155].key == 893472348628 {} 

私は多分それはそれとは何かを持っている、RAM 8GBので、64ビットのLinuxマシンを持っている:リリースモードは、これらの行を無視するので、私はデバッグモードでそれをコンパイルしたのですか?

+1

あなたの投稿にあなたが行った編集をお勧めしたいと思います。質問は、今より多くの*良い状態にあり、答えが得られる程度に十分です。 – Shepmaster

答えて

4

時間がかかる要素にアクセスしていませんが、ベクトルを初期化しています。確かに、あなたの例で私が手:

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 

私は、次の取得nowtt後に初期化する場合:

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 })。

0Element { 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 cases0u64のためのものを含むもあります!これはRawVec::with_capacity_zeroed(n)を使用します。間違いなく、この特殊なケースは速度がどこから来るのかです。

+0

おそらくリリースモードでは、オプティマイザは 'Element'構造体を"見て "それを文字通り' u64'にして、同じ特殊なケーシングのロックを解除しますか? – Shepmaster

+0

私は確かにそう望みます。 – mcarton

関連する問題