Rust: ThreadRngのパフォーマンスのバグ

作成日 2017年07月08日  ·  3コメント  ·  ソース: rust-lang/rust

ThreadRngは、JavaのThreadLocalRandomよりも5倍遅く動作します。

私はこのベンチマークをRustで実行します。

#[bench]
fn bench_rnd(b: &mut Bencher) {
    b.iter(|| rand::thread_rng().gen_range::<f64>(2.0, 100.0));
}

私のラップトップでは、結果は次のとおりです。
テストテスト:: bench_rnd ...ベンチ:49 ns / iter(+/- 1)

しかし、JHMで同じベンチマークを実行すると、次のようになります。

<strong i="12">@Benchmark</strong>
public double testRnd() {
    return ThreadLocalRandom.current().nextDouble(2, 100);
}

私のラップトップでは、結果は次のとおりです。
ベンチマークモードCntスコアエラー単位
Main.testRnd avgt 209,018±0,094ns / op

したがって、5.44倍の違いはパフォーマンスのバグのように見えます。

メタ

さび:

rbose
rustc 1.20.0-毎晩(c9bb93576 2017-06-24)
バイナリ:rustc
コミットハッシュ:c9bb93576d4484edd1b3c40eb2aea0dfa0788851
コミット日:2017-06-24
ホスト:x86_64-unknown-linux-gnu
リリース:1.20.0-毎晩
LLVMバージョン:4.0

Java:
OpenJDK 1.8.131

最も参考になるコメント

randは独自のリポジトリを持つ外部クレートであるため、これがRustのせいであり、 randのせいではないことを何らかの方法で証明できない限り、この問題はおそらくそこに属します。

しかし、あなたが本当に尋ねるべき質問は、あなたはどんな種類の乱数を手に入れているのかということです。 rand::ThreadRngは暗号的に安全なRNGであるため、それほど安全である必要のないRNGに固有のパフォーマンス上の欠点があります。 ドキュメントを見ると...「ThreadLocalRandomのインスタンスは暗号的に安全ではありません。」これは、公正な比較さえ行っていないことを意味します。

書かれたとおりにベンチマークを実行することは、私にとって21ns / iterです。

thread_rng()の結果をキャッシュするようにベンチマークを変更すると、15 ns / iter高速化されます。

#[bench]
fn bench_rnd(b: &mut Bencher) {
    let mut rng = rand::thread_rng();
    b.iter(|| rng.gen_range::<f64>(2.0, 100.0));
}

ただし、 weak_rng()を使用して暗号化セキュリティを破棄すると、3 ns / iterまで競合します。

#[bench]
fn bench_rnd(b: &mut Bencher) {
    let mut rng = rand::weak_rng();
    b.iter(|| rng.gen_range::<f64>(2.0, 100.0));
}

全てのコメント3件

randは独自のリポジトリを持つ外部クレートであるため、これがRustのせいであり、 randのせいではないことを何らかの方法で証明できない限り、この問題はおそらくそこに属します。

しかし、あなたが本当に尋ねるべき質問は、あなたはどんな種類の乱数を手に入れているのかということです。 rand::ThreadRngは暗号的に安全なRNGであるため、それほど安全である必要のないRNGに固有のパフォーマンス上の欠点があります。 ドキュメントを見ると...「ThreadLocalRandomのインスタンスは暗号的に安全ではありません。」これは、公正な比較さえ行っていないことを意味します。

書かれたとおりにベンチマークを実行することは、私にとって21ns / iterです。

thread_rng()の結果をキャッシュするようにベンチマークを変更すると、15 ns / iter高速化されます。

#[bench]
fn bench_rnd(b: &mut Bencher) {
    let mut rng = rand::thread_rng();
    b.iter(|| rng.gen_range::<f64>(2.0, 100.0));
}

ただし、 weak_rng()を使用して暗号化セキュリティを破棄すると、3 ns / iterまで競合します。

#[bench]
fn bench_rnd(b: &mut Bencher) {
    let mut rng = rand::weak_rng();
    b.iter(|| rng.gen_range::<f64>(2.0, 100.0));
}

また、JavaのThreadLocalRandomは非常に単純な線形合同PRNGであり、Rustのrandthread_rng()ISAAC(主張されている)の暗号的に安全なPRNGに基づいて

説明ありがとうございます。

このページは役に立ちましたか?
0 / 5 - 0 評価