问题描述
简介:
我很好奇将小数存储为位打包无符号整数与字节向量的性能差异(cpu 和内存使用情况)
示例
我将使用存储 RGBA 值的示例。它们是 4 个字节,因此很容易将它们存储为 u32
。
但是,将它们存储为 u8
类型的向量会更具可读性。
作为一个更详细的例子,假设我想存储和检索颜色 rgba(255,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,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
最后,内存使用的区别是否简单到仅在堆栈上为 u32
存储 32 位与在堆栈上为指针 v
存储 64 位以及在指针上存储 32 位一样简单? v
的值的堆?
对不起,如果这个问题有点令人困惑
解决方法
使用 Vec
会更贵;正如您提到的,它将需要执行堆分配,并且访问也将进行边界检查。
也就是说,如果您改用数组 [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,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 时,u32
与 [u8; 4]
对这些类型的操作的性能总体上应该是相同的。
tl;dr 使用结构:
struct Color {
r: u8,g: u8,b: u8,a: u8,}
也许也可以使用 repr(packed)
。
它为您提供了世界上最好的东西,您可以为频道命名。
这些成本是否足以使比特包装值得?
堆分配具有巨大成本。
有人可以立即就这两种操作的缺点给出任何见解吗?
与分配内存相比,两者都是噪音。