Ich wollte etwas über Rust-Aufgaben lernen, also habe ich eine Monte-Carlo-Berechnung von PI durchgeführt. Jetzt ist mein Rätsel, warum die Single-Threaded-C-Version viermal schneller ist als die 4-Wege-Threaded-Rust-Version. Offensichtlich mache ich etwas falsch, oder mein mentales Leistungsmodell ist weit davon entfernt.
Hier die C-Version:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#define PI 3.1415926535897932
double monte_carlo_pi(int nparts)
{
int i, in=0;
double x, y;
srand(getpid());
for (i=0; i<nparts; i++) {
x = (double)rand()/(double)RAND_MAX;
y = (double)rand()/(double)RAND_MAX;
if (x*x + y*y < 1.0) {
in++;
}
}
return in/(double)nparts * 4.0;
}
int main(int argc, char **argv)
{
int nparts;
double mc_pi;
nparts = atoi(argv[1]);
mc_pi = monte_carlo_pi(nparts);
printf("computed: %f error: %f\n", mc_pi, mc_pi - PI);
}
Die Rust-Version war kein Line-by-Line-Port:
use std::rand;
use std::rand::distributions::{IndependentSample,Range};
fn monte_carlo_pi(nparts: uint ) -> uint {
let between = Range::new(0f64,1f64);
let mut rng = rand::task_rng();
let mut in_circle = 0u;
for _ in range(0u, nparts) {
let a = between.ind_sample(&mut rng);
let b = between.ind_sample(&mut rng);
if a*a + b*b <= 1.0 {
in_circle += 1;
}
}
in_circle
}
fn main() {
let (tx, rx) = channel();
let ntasks = 4u;
let nparts = 100000000u; /* I haven't learned how to parse cmnd line args yet!*/
for _ in range(0u, ntasks) {
let child_tx = tx.clone();
spawn(proc() {
child_tx.send(monte_carlo_pi(nparts/ntasks));
});
}
let result = rx.recv() + rx.recv() + rx.recv() + rx.recv();
println!("pi is {}", (result as f64)/(nparts as f64)*4.0);
}
Erstellen und timen Sie die C-Version:
$ clang -O2 mc-pi.c -o mc-pi-c; time ./mc-pi-c 100000000
computed: 3.141700 error: 0.000108
./mc-pi-c 100000000 1.68s user 0.00s system 99% cpu 1.683 total
Erstellen und timen Sie die Rust-Version:
$ rustc -v
rustc 0.12.0-nightly (740905042 2014-09-29 23:52:21 +0000)
$ rustc --opt-level 2 --debuginfo 0 mc-pi.rs -o mc-pi-rust; time ./mc-pi-rust
pi is 3.141327
./mc-pi-rust 2.40s user 24.56s system 352% cpu 7.654 tota
Kompilieren Sie nicht mit aktivierten Debugging-Symbolen.
– AndyG
9. Oktober 2014 um 14:07 Uhr
the single-threaded C version is 4 times slower than the 4-way threaded Rust version
. Die Zahlen, die Sie gepostet haben, scheinen umgekehrt zu sein– Benutzer703016
9. Oktober 2014 um 14:07 Uhr
@RobLatham Der Engpass hier ist wahrscheinlich der Zufallszahlengenerator. Versuchen
rand::XorShiftRng::new_unseeded()
Anstatt vonrand::task_rng()
für einen schnelleren Zufallsgenerator.– Dogbert
9. Oktober 2014 um 14:47 Uhr
Sie können ein zufälliges Seed erstellen
XorShiftRng
z.Blet mut rng: XorShiftRng = rand::random();
(Die Geschwindigkeitsverbesserung ergibt sich aus der Änderung des Algorithmus, nicht aus dem Mangel an Seeding).– huon
9. Oktober 2014 um 22:01 Uhr
jetzt ist es eher so. Auf einem 4-Kern-System ist Vier-Wege-Threaded-Rost 4,5-mal schneller als die Single-Threaded-C-Version. Ich werde Dogberts Antwort akzeptieren, wenn er sie aufschreiben möchte, oder ich werde in ein paar Tagen selbst antworten.
– Rob Latham
10. Oktober 2014 um 2:26 Uhr