将字节打包到u32与将它们存储在vec<u8>中的性能差异?
介绍:
我很好奇将小数存储为位打包无符号整数与字节向量的性能差异(cpu 和内存使用量)
例子
我将使用存储 RGBA 值的示例。它们是 4 个字节,因此很容易将它们存储为u32.
但是,将它们存储为类型的向量会更具可读性u8。
作为一个更详细的例子,假设我想存储和检索颜色 rgba(255,0,0,255)
这就是我将如何去做这两种方法:
// Bitpacked:
let i: u32 = 4278190335;
//binary is 11111111 00000000 00000000 11111111
//In reality I would most likely do something more similar to:
let i: u32 = 255 << 24 + 255; //i think this syntax is right
// Vector:
let v: Vec<u8> = [255,0,0,255];
然后可以查询这两个红色值
i >> 24
//or
&v[0]
//both expressions evaluate to 255 (i think. I'm really new to rust <3 )
问题 1
据我所知, 的值v必须存储在堆上,因此存在与此相关的性能成本。这些成本是否足以使位包装值得?
问题2
然后是两个表达式i >> 24和&v[0]。我不知道 Rust 在位移位与从堆中获取值的速度有多快。我会测试它,但我暂时无法访问安装了 Rust 的机器。有人可以立即了解这两种操作的缺点吗?
问题 3
最后,内存使用的差异是否就像仅在堆栈上存储 32 位u32用于指针v与在堆栈上存储 64 位用于指针以及在堆上存储32 位的值一样简单v?
对不起,如果这个问题有点混乱
回答
使用 aVec会更贵;正如您提到的,它将需要执行堆分配,并且访问也将进行边界检查。
也就是说,如果您改用数组[u8; 4],则与位打包u32表示相比的性能应该几乎相同。
实际上,请考虑以下简单示例:
pub fn get_red_bitpacked(i: u32) -> u8 {
(i >> 24) as u8
}
pub fn get_red_array(v: [u8; 4]) -> u8 {
v[3]
}
pub fn test_bits(colour: u8) -> u8 {
let colour = colour as u32;
let i = (colour << 24) + colour;
get_red_bitpacked(i)
}
pub fn test_arr(colour: u8) -> u8 {
let v = [colour, 0, 0, colour];
get_red_array(v)
}
我查看了Compiler Explorer,编译器决定了这一点,get_red_bitpacked并且get_red_array完全相同:以至于它甚至没有为前者生成代码。这两个“测试”功能显然也针对完全相同的程序集进行了优化。
example::get_red_array:
mov eax, edi
shr eax, 24
ret
example::test_bits:
mov eax, edi
ret
example::test_arr:
mov eax, edi
ret
显然这个例子被编译器看穿了:为了进行适当的比较,你应该用实际代码进行基准测试。也就是说,我觉得相当有把握地说,使用 Rust ,这些操作的u32vs性能[u8; 4]通常应该是相同的。