我应该通过引用还是值传递一个大数组?
Should I pass a large array by reference or value?
我正在用 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.
我 运行 对这两个选项进行了基准测试,似乎无论优化器是打开还是关闭,通过指针传递的速度都快得多(正如预期的那样)。
不过有趣的是,如果关闭优化器,按值传递会稍微快一些,如下所示:
➜ 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)
我的问题是:按引用传递比按值传递有意义的字节阈值是多少?
我无法直接回答您的问题,因为与许多其他问题一样,这取决于代码的位置、代码周围的代码在做什么、访问模式是什么等等。如果您关心性能,您必须分析。
也就是说...
"Large" 在 Rust 中按值传递的值 实际上 通过引用传递作为优化。通过 "large",我相信它比几个指针更大。同样,这是一个优化,因此您依赖编译器在这里做出合理的选择。在大多数情况下,它应该选择正确。
还要记住,您自己不能"pass logically by value, actually by reference"(编译器正在做的事情);这意味着使用 &move
参考,该语言中尚不存在。
我认为史蒂夫的评论应该被更自由地解释为:"don't override the compiler yourself unless profiling tells you to."
那么两者有什么区别吗?是的!如果你传递一个 [u8; 0x2000]
,那么调用者必须在传递它之前制作一个 copy 的值,假设你希望以后能够再次使用它。这可能是性能差异的来源。
请注意,如果您将值移动到函数中,编译器不会制作副本。这包括所有不可复制的类型(如 Box
、String
和 Vec
),并且 应该 包括编译器知道你不是的可复制类型不会再用了。
合适的选择是 &[u8; 0x2000]
因为:
- 你只需要读取值(即如果你想修改它,你需要一个
&mut [u8; 0x2000]
.
- 您不想获得该值的所有权(在这种情况下,您将按值传递)。
再次强调:不要开始用"this is a big value therefore I will use pass-by-reference"玩游戏,因为编译器已经这样做了,你真的很难搞定手动正确。
我正在用 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.
我 运行 对这两个选项进行了基准测试,似乎无论优化器是打开还是关闭,通过指针传递的速度都快得多(正如预期的那样)。
不过有趣的是,如果关闭优化器,按值传递会稍微快一些,如下所示:
➜ 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)
我的问题是:按引用传递比按值传递有意义的字节阈值是多少?
我无法直接回答您的问题,因为与许多其他问题一样,这取决于代码的位置、代码周围的代码在做什么、访问模式是什么等等。如果您关心性能,您必须分析。
也就是说...
"Large" 在 Rust 中按值传递的值 实际上 通过引用传递作为优化。通过 "large",我相信它比几个指针更大。同样,这是一个优化,因此您依赖编译器在这里做出合理的选择。在大多数情况下,它应该选择正确。
还要记住,您自己不能"pass logically by value, actually by reference"(编译器正在做的事情);这意味着使用
&move
参考,该语言中尚不存在。我认为史蒂夫的评论应该被更自由地解释为:"don't override the compiler yourself unless profiling tells you to."
那么两者有什么区别吗?是的!如果你传递一个
[u8; 0x2000]
,那么调用者必须在传递它之前制作一个 copy 的值,假设你希望以后能够再次使用它。这可能是性能差异的来源。请注意,如果您将值移动到函数中,编译器不会制作副本。这包括所有不可复制的类型(如
Box
、String
和Vec
),并且 应该 包括编译器知道你不是的可复制类型不会再用了。
合适的选择是 &[u8; 0x2000]
因为:
- 你只需要读取值(即如果你想修改它,你需要一个
&mut [u8; 0x2000]
. - 您不想获得该值的所有权(在这种情况下,您将按值传递)。
再次强调:不要开始用"this is a big value therefore I will use pass-by-reference"玩游戏,因为编译器已经这样做了,你真的很难搞定手动正确。