我已经在 Rust 中编写了一个遗传算法来熟悉 Rust。当我运行代码时,我发现 ( cargo run
) 和 ( cargo run --release
) 版本之间存在极端的性能差异。我发现创建随机初始化基因的代码对此负责。
我搜索了是否有办法查看由 Rust 编译器优化的代码,并发现在 Rust Playground 上是可能的。所以我去了,看到一堆汇编代码,我不知道如何阅读。
以下代码是我提供给 Rust 游乐场的代码。(对不起,代码很脏。我对编程很陌生。)
在没有优化(cargo run
)的情况下编译时,平均需要 160 秒才能运行。
使用 optimizations( cargo run --release
)编译时,平均需要 3 秒才能运行。
编译器可能正在执行哪些确切的优化方法来导致这种巨大的性能差异?
extern crate rand;
use rand::Rng;
use std::time::Instant;
fn make_genepool(position_list: &Vec<Vec<i8>>, size: i32) -> Vec<Vec<i8>>{
let mut genelist:Vec<Vec<i8>> = Vec::new();
let position_len = position_list.len();
let mut rand = rand::thread_rng();
let mut gene_rand:Vec<Vec<i8>> = Vec::new();
for i in 0..position_len{
let mut gene_insert:Vec<i8> = Vec::new();
let avail_move_len = position_list[i].len();
for _ in 0..size{
gene_insert.push(position_list[i][rand.gen_range(0, avail_move_len)]);
}
gene_rand.push(gene_insert);
}
for i in 0..size as usize{
let mut genelist_insert:Vec<i8> = Vec::new();
for j in 0..position_len{
genelist_insert.push(gene_rand[j][i]);
}
genelist.push(genelist_insert);
}
return genelist;
}
fn main(){
let mut rand = rand::thread_rng();
let mut test_data:Vec<Vec<i8>> = Vec::new();
for i in 0..4520{
let mut temp:Vec<i8> = Vec::new();
for j in 0..rand.gen_range(1, 9){
temp.push(rand.gen_range(1, 9));
}
test_data.push(temp);
}
let now = Instant::now();
let ans = make_genepool(&test_data, 16384);
println!("Time passed: {}", now.elapsed().as_secs_f64());
}
您必须比较优化和未优化代码的汇编代码,才能确定它真正在做什么。
但它可能是:
范围检查:如果您使用常量(例如代码中的 4520),则不需要范围检查。
循环展开:如果编译器知道每个循环运行的多种类型,它可能会简单地将循环体多次转换为相同的代码。
其他诸如内联函数等。
为了让你的代码运行得更快,你可以完全按照编译器在做的事情,但最好让编译器来做。编译器旨在优化您的代码是有原因的。
如果您只是想编写更高效的代码,请关注:
确保您的用例的算法是最佳的。算法的性能因输入的数据而异,因此即使理论上一种算法可能是最佳的,但对于您的数据,您的性能可能最差,而另一种算法可能更合适。
了解创建对象、销毁对象等(内存管理)时发生的事情。这将要求您学习该语言以了解它为您做什么。但是编写最有效的代码以便编译器不必猜测的努力可能不值得您花时间。例如,编译器使用了许多技术,例如分支预测等,这会让您自己做起来非常乏味。最好在您的代码已经正常工作之后才真正需要优化。
最后,这真的值得你花时间吗?也许你的时间专注于让你的代码工作会更好,然后让编译器为你优化它。随着时间的推移,无论如何你都会通过经验学习东西并编写更有效的代码(希望如此)。
如果此答案有帮助,请将其标记为正确。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句