高效地将字节数组转换为十进制

2024-01-19

如果我有一个字节数组并且想要转换该数组的连续 16 字节块,其中包含 .net 的表示形式Decimal, 转化为适当的Decimalstruct,最有效的方法是什么?

在我正在优化的情况下,以下代码在我的分析器中显示为最大的 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 and BinaryReader,我想喂养一系列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]);
}

This is 速度提高 10 倍 as the 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();
}

Result: Time: 1.68s serialization, 1.81s deserialization。这是我们的基线。我也尝试过Buffer.BlockCopy to an int[4],这为我们提供了 0.42 秒的反序列化时间。使用问题中描述的方法,反序列化时间降至 0.29 秒。

然而从理论上讲,可能有一种方法可以复制这 16 个连续的 byte 到内存中的其他位置并声明它是 Decimal, 没有任何检查。有人知道这样做的方法吗?

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

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。很确定这是最快的……不过,你必须接受这里的不安全,而且我认为内容的编写方式与读取方式相同。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

高效地将字节数组转换为十进制 的相关文章

随机推荐

  • 为什么我们不能使用友元函数重载“=”?

    为什么不允许使用友元函数重载 我写了一个小程序 但它给出了错误 class comp int real int imaginary public comp real 0 imaginary 0 void show cout lt lt Re
  • 何时过滤/清理数据:在数据库插入之前还是在显示之前?

    当我准备解决输入数据过滤和清理问题时 我很好奇是否有最佳 或最常用 的做法 是在将数据插入数据库之前过滤 清理数据 HTML JavaScript 等 更好 还是应该在准备以 HTML 形式显示数据时进行过滤 清理 一些注意事项 我正在 P
  • Rails 4 - ajax:成功未被触发

    我通过ajax提交表单 我可以在Chrome的网络面板中看到它成功并返回了一些JSON 但是 ajax success 事件永远不会被触发 为什么 Does not work despite getting success in the N
  • IIS 与 Windows 身份验证绑定

    我有一个本地网站 http localhost 测试站点 http localhost testsite 与 Windows 身份验证 效果很好 现在我将网站的绑定更改为 URL http testsite blablabla biz ht
  • 如何正确格式化QCompleter弹出列表的列表项?

    我想研究如何制作一个小型用户界面 用户可以在其中输入一些字母并根据给定的数据源 此处列出 获取一些建议 从而使搜索变得更容易 为此 我使用 Qt 的QCompleter class 在匹配元素中 键入的字母应使用 HTML 突出显示 如下面
  • 路径前缀 \??\ 和 \\?\

    前缀为 的路径有什么区别 以及那些前缀为 在 Windows 7 CMD 行 DIR 给出 Volume 00000000 0000 0000 0000 000000000000 WMIC 音量列表给出 Volume 00000000 00
  • 移动学生如何有效地使用带有源代码控制系统的 Dropbox?

    我买了一台笔记本电脑 为下个学期做准备 这将使我在全职工作的同时参加大学编程课程 当然 我会使用源代码控制系统 可能是 Subversion 并想到在我的 Dropbox 文件夹中创建我的存储库 这将使我能够使用我的笔记本电脑或台式机 或者
  • 错误:“y_true 中的类数不等于 'y_score' 中的列数”

    我有一个不平衡的多类数据集 当我尝试计算 roc auc score 时 我收到此错误 ValueError y true 中的类数不等于 y score 中的列数 这是代码 model svm SVC kernel linear prob
  • 使用 Firefox Addon SDK 列出所有驱动器

    是否有跨操作系统的方法来使用 firefox addon sdk 列出所有已安装驱动器 硬盘 USB 驱动器等 的路径 我找到了适用于 Windows 的代码 但找不到跨操作系统的解决方案 Components utils import r
  • LINQ to XML - 尝试通过元素的属性值选择元素列表

    我试图从 XML 文档中获取元素列表 其中节点具有特定的属性值 该文档的结构如下
  • 从 C# 中的函数返回类

    我可以从 C 中的函数返回类对象作为返回值 而不是返回 string 或 int 或 etc C 中的类对象是一种类型 所以你绝对可以从函数返回它 public Type Foo return typeof string public Ty
  • OpenMp 与 IOS/Android 的兼容性

    我正在尝试做什么 我正在研究C c 为所有平台构建产品的代码 我操作系统 Android Windows 移动 桌面 Mac Linux 到目前为止我做了什么 是的 有许多在线链接讨论 OpenMp 与不同处理器和操作系统的兼容性 但很难从
  • xmpp框架iOS新用户注册方法

    我已经开发了适用于 iOS 的 XMPP 聊天客户端 现在我正在研究如何从 iOS 本身进行新用户注册 任何人都可以帮助注册新用户的方法 因为它需要与服务器通信并将用户名和密码存储到服务器数据库中 请帮帮我 我已经搜索了两天了 NSMuta
  • cursor.fetchone() 返回 None 但数据库中的行存在

    我正在用 python 编写一个与 MySQL 数据库交互的程序 对于 sql 查询 我使用 MySQLdb 问题是fetchone 返回 None 但通过数据库浏览器我可以看到that行存在 这段代码 query SELECT FROM
  • 如何使用Python库生成后缀树? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我需要可以构建后缀树 特别是广义后缀树的Python库 你能给我推荐一些图书馆吗 谢谢 请参阅以下库
  • 在 JApplet 上运行的 JPanel

    我正在设计一个 JApplet 基本上这个小程序将允许用户绘制二次方程图 并插入 x 轴和 y 轴的范围 但要达到这一目标 还有很多工作要做 我仍处于设计界面的阶段 这是我的代码 import java awt Dimension impo
  • Spring启动-配置EntityManager

    我正在使用Google guice在我的项目中 现在我尝试将框架转换为SpringBoot完全 我配置了 Beanpersistence xml like below in Autowired Bean name transactionMa
  • Java awt.Robot:CTRL+ALT+DEL 未调出所需的屏幕

    我最近刚刚发现 awt Robot 库 我很高兴能够使用它 我以为我应该对我的朋友开个小恶作剧 让机器人按控制 Alt 删除按锁定计算机按钮 但我无法让程序调出控制 Alt 删除屏幕 这是我的代码 import java awt impor
  • 构建发布时出现颤动警告

    当我尝试构建 release 我的应用程序时 我不断收到这些红色警告 尝试扑干净 flutter clean cache 没有任何作用 所有包都是最新的 我的构建 Gradle buildscript ext kotlin version
  • 高效地将字节数组转换为十进制

    如果我有一个字节数组并且想要转换该数组的连续 16 字节块 其中包含 net 的表示形式Decimal 转化为适当的Decimalstruct 最有效的方法是什么 在我正在优化的情况下 以下代码在我的分析器中显示为最大的 CPU 消耗者 p