Rob*_*ham 15 c performance rust
我想学习一些关于生锈任务的知识,所以我做了一个蒙特卡罗计算PI.现在我的难题是为什么单线程C版本比4路线程Rust版本快4倍.显然,我做错了什么,或者我的心理表现模型已经过时了.
这是C版本:
#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);
}
Run Code Online (Sandbox Code Playgroud)
Rust版本不是逐行端口:
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);
}
Run Code Online (Sandbox Code Playgroud)
构建和计算C版本:
$ 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
Run Code Online (Sandbox Code Playgroud)
构建和修改Rust版本:
$ 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
Run Code Online (Sandbox Code Playgroud)
Rob*_*ham 13
正如Dogbert观察到的那样,瓶颈是随机数发生器.这是一个在每个线程上快速播种的方法
fn monte_carlo_pi(id: u32, nparts: uint ) -> uint {
...
let mut rng: XorShiftRng = SeedableRng::from_seed([id,id,id,id]);
...
}
Run Code Online (Sandbox Code Playgroud)
小智 9
有意义的基准测试是一件棘手的事情,因为您有各种优化选项等。此外,代码结构也会产生巨大影响。
比较 C 和 Rust 有点像比较苹果和橙子。我们通常使用计算密集型算法,如您在上面描述的算法,但现实世界可能会给您带来麻烦。
话虽如此,总的来说,Rust 可以并且确实接近 C 和 C++ 的性能,并且大多数人可以在并发任务上做得更好。
看看这里的基准:
https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/rust-clang.html
我选择了 Rust 与 Clang 基准比较,因为两者都依赖于底层的 LLVM。
另一方面,与 C gcc 的比较会产生不同的结果:
你猜怎么着?Rust 仍然领先!
我恳请您更详细地浏览 Benchmark Game 网站。在某些情况下,C 在某些情况下会超越 Rust。
通常,在创建实际解决方案时,您希望针对特定情况进行性能基准测试。始终这样做,因为您经常会对结果感到惊讶。永远不要假设。
我认为很多时候,基准测试被用来转发“我的语言比你的语言更好”的 rwars 风格。但作为一个在他漫长的职业生涯中使用过 20 多种计算机语言的人,我总是说这是工作的最佳工具。