我正在Rust中构建一个Game Boy模拟器。我创建了一个readByteFromMemory()函数,它将8KB数组作为参数,表示Game Boy的内存为8KB。我在考虑两种选择:
fn readByteFromMemory(internalRAM: [u8;0x2000]) -> u8
或
fn readByteFromMemory(internalRAM: &[u8;0x2000]) -> u8
我唯一可以找到引用此主题的内容是本文:http://words.steveklabnik.com/pointers-in-rust-a-guide,其中指出:
But don’t reach for that pointer until you must! Make sure that the
struct is large enough by performing some tests before you add in the
complexity of pointers.
我对这两个选项进行了基准测试,似乎无论优化器是打开还是关闭,指针1的传递都要快得多(正如预期的那样)。
虽然有趣的是,如果关闭优化器,传递值会略快一些:
➜ rustTest$ rustc --test -O passByTest.rs
➜ rustTest$ ./passByTest --bench
running 2 tests
test ptrBench ... bench: 1 ns/iter (+/- 0)
test valueBench ... bench: 221 ns/iter (+/- 2)
test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured
➜ rustTest$ rustc --test passByTest.rs
➜ rustTest$ ./passByTest --bench
running 2 tests
test ptrBench ... bench: 13 ns/iter (+/- 3)
test valueBench ... bench: 152 ns/iter (+/- 1)
我的问题是:什么似乎是以字节为单位的阈值,通过引用传递对传递值有意义?
答案 0 :(得分:1)
我无法直接回答你的问题,因为正如许多其他事情一样,它取决于代码的位置,它周围的代码在做什么,访问模式是什么,等等,等等,等等。如果您对性能感到担心,您必须对进行分析。
那说......
"大"在Rust中通过值传递的值实际通过引用传递为优化。通过" large",我相信它比任何指针更重要。同样,这是一个优化,所以你依靠编译器在这里做出合理的选择。在大多数情况下,它应该正确选择。
另请注意,您无法按价值逻辑传递,实际上是通过参考" (这是编译器正在做的事情)你自己;这意味着使用&move
引用,但该语言尚不存在。
我相信史蒂夫的评论应该更加自由地解释为:"不要自己覆盖编译器除非分析告诉你。&#34
两者之间有什么区别吗?是!如果您传递[u8; 0x2000]
,则调用者必须在传递值之前制作值的副本,假设您希望以后能够再次使用它。这可能是绩效差异的来源。
请注意,如果要将值移动到函数中,编译器不会复制。这包括所有不可复制的类型(例如Box
,String
和Vec
),而 应包含编译器知道您不可复制的可复制类型再次使用。
适当的选择是&[u8; 0x2000]
因为:
&mut [u8; 0x2000]
。再次强调:不要开始玩#34;这是一个很大的价值,因此我将使用传递参考"因为编译器已经这样做了,而且你很难手动完成它。