【发布时间】:2013-06-07 08:07:10
【问题描述】:
如果我有一个字节数组,并且想要将该数组的连续 16 字节块(包含 .net 的 Decimal 表示)转换为正确的 Decimal 结构,那么最有效的方法是什么?
在我正在优化的情况下,这是在我的分析器中显示为最大 CPU 消耗者的代码。
public static decimal ByteArrayToDecimal(byte[] src, int offset)
{
using (MemoryStream stream = new MemoryStream(src))
{
stream.Position = offset;
using (BinaryReader reader = new BinaryReader(stream))
return reader.ReadDecimal();
}
}
为了摆脱MemoryStream 和BinaryReader,我认为将BitConverter.ToInt32(src, offset + x)s 的数组输入Decimal(Int32[]) 构造函数会比我在下面提供的解决方案更快,但下面的版本很奇怪,快两倍。
const byte DecimalSignBit = 128;
public static decimal ByteArrayToDecimal(byte[] src, int offset)
{
return new decimal(
BitConverter.ToInt32(src, offset),
BitConverter.ToInt32(src, offset + 4),
BitConverter.ToInt32(src, offset + 8),
src[offset + 15] == DecimalSignBit,
src[offset + 14]);
}
这是MemoryStream/BinaryReader 组合的10 倍,我用一堆极值对其进行了测试以确保它有效,但十进制表示并不像其他原始类型,所以我还不相信它适用于 100% 的可能十进制值。
然而,理论上,有一种方法可以将这 16 个连续字节复制到内存中的其他位置,并声明为十进制,无需任何检查。有人知道这样做的方法吗?
(只有一个问题:虽然小数表示为 16 个字节,但一些可能的值不构成有效的小数,所以不检查memcpy 可能会破坏事情......)
或者还有其他更快的方法吗?
【问题讨论】:
-
是否存在数组中连续有多个十进制值的情况?如果没有,我想不出更快的方法。
-
这里的问题不是 BinaryReader 这么慢,而是 Decimal 构造函数非常快。因此,构建这些对象的开销在 A/B 测试中变得很明显。安全和速度是相互矛盾的目标。
-
@HansPassant 我没说
BinaryReader很慢。但是,不管它们有多快,经历任何不必要的间接显然都会减慢速度。如果我有一个BinaryReader开头,而不是一个字节数组,我怀疑有什么比调用它的ReadDecimal方法更快的方法从它读取小数。