gpt4 book ai didi

c# - 有效地将字节数组转换为十进制

转载 作者:太空狗 更新时间:2023-10-30 00:53:17 25 4
gpt4 key购买 nike

如果我有一个字节数组并想将该数组的一个连续的 16 字节 block (包含 .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();
}
}

为了摆脱 MemoryStreamBinaryReader,我想将一组 BitConverter.ToInt32(src, offset + x) 放入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]);
}

这是 10 倍的速度 MemoryStream/BinaryReader 组合,我用一堆极值测试它以确保它有效,但十进制表示不像其他基本类型那样简单,所以我还不相信它适用于 100% 的可能十进制值。

然而理论上,可以有一种方法可以将这 16 个连续字节复制到内存中的某个其他位置,并将其声明为 Decimal,而无需任何检查。有人知道这样做的方法吗?

(只有一个问题:虽然小数表示为 16 个字节,但一些可能的值不构成有效的小数,因此执行未经检查的memcpy 可能会破坏事情...)

或者还有其他更快的方法吗?

最佳答案

尽管这是一个老问题,但我还是有点好奇,所以决定进行一些实验。让我们从实验代码开始吧。

static void Main(string[] args)
{
byte[] serialized = new byte[16 * 10000000];

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; ++i)
{
decimal d = i;

// Serialize
using (var ms = new MemoryStream(serialized))
{
ms.Position = (i * 16);
using (var bw = new BinaryWriter(ms))
{
bw.Write(d);
}
}
}
var ser = sw.Elapsed.TotalSeconds;

sw = Stopwatch.StartNew();
decimal total = 0;
for (int i = 0; i < 10000000; ++i)
{
// Deserialize
using (var ms = new MemoryStream(serialized))
{
ms.Position = (i * 16);
using (var br = new BinaryReader(ms))
{
total += br.ReadDecimal();
}
}
}
var dser = sw.Elapsed.TotalSeconds;

Console.WriteLine("Time: {0:0.00}s serialization, {1:0.00}s deserialization", ser, dser);
Console.ReadLine();
}

结果:时间:1.68s 序列化,1.81s 反序列化。这是我们的底线。我还尝试将 Buffer.BlockCopy 转换为 int[4],这为我们提供了 0.42 秒的反序列化时间。使用问题中描述的方法,反序列化下降到 0.29s。

In theory however, there could be a way to copy those 16 contiguous byte to some other place in memory and declare that to be a Decimal, without any checks. Is anyone aware of a method to do this?

是的,最快的方法是使用不安全的代码,这在这里没问题,因为小数是值类型:

static unsafe void Main(string[] args)
{
byte[] serialized = new byte[16 * 10000000];

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; ++i)
{
decimal d = i;

fixed (byte* sp = serialized)
{
*(decimal*)(sp + i * 16) = d;
}
}
var ser = sw.Elapsed.TotalSeconds;

sw = Stopwatch.StartNew();
decimal total = 0;
for (int i = 0; i < 10000000; ++i)
{
// Deserialize
decimal d;
fixed (byte* sp = serialized)
{
d = *(decimal*)(sp + i * 16);
}

total += d;
}
var dser = sw.Elapsed.TotalSeconds;

Console.WriteLine("Time: {0:0.00}s serialization, {1:0.00}s deserialization", ser, dser);

Console.ReadLine();
}

此时,我们的结果是:Time: 0.07s serialization, 0.16s deserialization。很确定这是最快的速度...不过,您必须在这里接受不安全,并且我假设内容的编写方式与读取方式相同。

关于c# - 有效地将字节数组转换为十进制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16979164/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com