当把call函数注解后,或是注解println! 都可以快速运行。
在 https://play.rust-lang.org/ 上有时候可以 ""使用println! "" 而且依然编译的很快,有时候则不行,我自己本地电脑都不行。
这效能差了十万八千里,请大家帮忙,新手总是在 println! 跌坑。
这边使用 cargo run --release
编译
use std::time::{Duration, Instant};
struct Struct {
a: String,
b: bool,
}
trait Dyn {}
impl Dyn for Struct {}
fn main() {
let start = Instant::now();
let mut count = 0;
let count_end = 100_000_000i64;
while count <= count_end {
let m: Box<Struct> = Box::new(Struct {
b: false,
a: "str".to_string(),
});
if count == count_end {
call(); // ---- 这儿
m.b;
m.a;
}
count += 1;
}
let duration = start.elapsed();
println!("Time: {:?}", duration);
}
fn call(){
println!("run call()\n"); // ---- 重点在这儿,注解后变超快
}
Time:
😫使用println! | 😄注解//println! |
---|---|
12.863911s | 2.8486ms |
13.2101748s | 2.4661ms |
13.5353751s | 2.0433ms |
13.4852107s | 1.7869ms |
———————— | ———————— |
1
共 18 条评论, 1 页
评论区
写评论已经有结论了
我也想看懂汇编,不过太难了,有工具可以帮忙把汇编转化的人性化点吗😂。
感謝 7sDream 的解說,我回去測了一段,既然是把 m 的堆分配沒了,那就一定可以寫出不使用 println! 仍然繞過編譯器優化。 我加入了...一樣不使用 println! 耗時 13s ,這裡不使用彙編情況下證明了 7sDream 的推斷(不會看汇编只好盲式繞過編譯氣優化)。
--
👇
7sDream: 随便试了一个 Case:
其他的可以自己看。
这种问题不要靠猜测,看汇编是最快最有效的。
感谢,又长知识了,原来lock还有这层用法。
--
👇
peacess: lock要在循环的外面,因为每一次调用print时都lock与unlock一次,这是它性能差的原因,所以要提高性能,要把lock放在循环外面,打印多次,只需要一次lock与unlock来提高效率,这样性会有提高。但是由于输出console的io耗时这个是没有办法的,除非不使用console输出。
lock要在循环的外面,因为每一次调用print时都lock与unlock一次,这是它性能差的原因,所以要提高性能,要把lock放在循环外面,打印多次,只需要一次lock与unlock来提高效率,这样性会有提高。但是由于输出console的io耗时这个是没有办法的,除非不使用console输出。
--
👇
swdcgghxa: 按你的思路,式过了,和println!结果一样。
对了这是markdown 格式所以程式码要用三个 ` 将程式码包起来结束后也要有三个
--
👇
peacess: print的性能确实不行, 如果一定要使用,下面的方法,可以改进性能
你这println一旦注释掉,整个循环就完全无副作用了,要我是编译器,就会直接把整个循环都丢掉。
不过其实写了println理论上也可以优化,按理来说这个if里的内容能直接在编译时分析出执行完之后就退出循环,应该移到循环后面去,然后前面循环也因此无副作用,再把循环丢掉,就只剩一句call了(call也可以内联掉),可能是编译器还没这个水平。
开优化之后对运行结果和时间有疑问建议直接看汇编,你看rust代码是分析不出什么东西的,因为编译器可能会给你优化的面目全非。各个代码之间是有影响的,就算你发现你写了println程序变慢了,也不一定是println才导致慢,可能是因为你写了之后,某些优化条件不成立了,才导致慢。
随便试了一个 Case:
其他的可以自己看。
这种问题不要靠猜测,看汇编是最快最有效的。
你可以用 https://godbolt.org/ 这个网站看一下编译出来的汇编结果。
所有耗时在毫秒级和纳秒级别的 Case,堆分配(甚至是整个循环)应该都被优化了,否则速度是不可能那么快的。
按你的思路,式过了,和println!结果一样。
对了这是markdown 格式所以程式码要用三个 ` 将程式码包起来结束后也要有三个
--
👇
peacess: print的性能确实不行, 如果一定要使用,下面的方法,可以改进性能
我测试之后,效能延迟显然不是堆内存所导致的,而且回圈也似乎不是进行
初始状态到循环执行完毕的变化记录优化
,因为按Rust 规则大括弧意味着新的作用域且结束后释放,我测试将其放入大括弧,但并没有比没大括弧有太多效能差距。--
👇
madolchepalooza、7sDream
我做了一次更改,让 m 变数一定会被修改,这效能快的很。
还特别在外围加上大跨号保证一定会在每次回圈中逐次执行,让他一定分配及销毁。
https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=2e8668acb46b2c338dfb0a9d70384bd0
Time: 2.2517ms
Time: 2.6009ms
Time: 2.0037ms
Time: 3.3287ms
测一个不加上大挂号
https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=75eee069d7dc1b2c659ed5d81fa6a348
Time: 2.9961ms
Time: 2.4795ms
Time: 2.5618ms
Time: 3.6779ms
测一个把 m 那行都取消掉,且有println!
https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=e4207459c76b8946a31583d5b583b449
Time: 60.0766ms
Time: 64.3458ms
Time: 66.9781ms
Time: 72.9777ms
最后连println! 也都取消掉
https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=6812812473cc8e7dca35063ab6c8b715
Time: 300ns
Time: 200ns
Time: 300ns
Time: 600ns
--
👇
madolchepalooza 👇 7sDream
正如7sDream所说,如果把堆内存分配那句去掉,运行时间能够显著缩短;
一般来说循环优化一个比较显然的思路就是,只需要把其初始状态到循环执行完毕的变化记录下来就行,不必逐次执行;但如果在这个循环块中有print等等会修改外界存储状态(比如显存)的代码存在,那么就难以进行这种优化,因为不好推测这次修改是否依赖循环过程中产生的局部变量。而如果这种优化以函数为单位进行(只要函数非纯则不优化),那么如果在循环块中有非纯函数调用,就会导致这种情况发生。编译原理没学明白😂现查现用
其实我想说,效能什么的,C++的效能在现阶段还有不少优于Rust的地方;个人感觉Rust最大的优势就是满足较高的性能同时,基本没有历史包袱,能用上各种新的编程语言特性,而且还有Cargo等等先进的工具链;所以没必要单独因为性能问题决定是否要使用一种PL
--
👇
swdcgghxa: 什么意思,println!影响优化???
😭😭 那Rust 的效能是个惊喜吗,我就是冲着它这个效能来的。
就列印一次效能就没有了,尴尬
println!
成本太高了,都别用println!
除错了😂😂--
👇
madolchepalooza: 感觉println只是个诱因...可能println这种IO行为把这个while块变成非纯的了,所以没法优化掉,只能逐一执行
毕竟你这里println理论上只执行一次啊😂 [[[ 4阿~~~~ ]]]
print的性能确实不行, 如果一定要使用,下面的方法,可以改进性能
use std::io::Write; { let mut stdout = std::io::stdout(); let mut lock = stdout.lock(); for line in lines { writeln!(lock, "{}", line)?; } }
怀疑是你注释掉之后,这个函数就空了,所以编译器可以很有自信的判断出 Box 的那个变量从来没有被使用过,然后这个循环就直接优化掉了。
所以你这里最耗时的不是
println!
,而是 Box 带来的堆上内存分配。什么意思,println!影响优化???
😭😭 那Rust 的效能是个惊喜吗,我就是冲着它这个效能来的。
就列印一次效能就没有了,尴尬
println!
成本太高了,都别用println!
除错了😂😂--
👇
madolchepalooza: 感觉println只是个诱因...可能println这种IO行为把这个while块变成非纯的了,所以没法优化掉,只能逐一执行
毕竟你这里println理论上只执行一次啊😂 [[[ 4阿~~~~ ]]]
程式这边写的是
if count == 100000000i64
所以只有跑一次,并没有列印很多行的问题。👇 rayw0ng: 所有语言都有这个问题,尤其是终端渲染输出字符更费时。如果重定向输出到 /dev/null ,就会快很多。
👇 johnmave126: stdout输出确实挺慢的,println每行都会flush,加上你这个打印次数确实不少。不奇怪
感觉println只是个诱因...可能println这种IO行为把这个while块变成非纯的了,所以没法优化掉,只能逐一执行
毕竟你这里println理论上只执行一次啊😂
所有语言都有这个问题,尤其是终端渲染输出字符更费时。如果重定向输出到
/dev/null
,就会快很多。stdout输出确实挺慢的,println每行都会flush,加上你这个打印次数确实不少。不奇怪