加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

如何使用ruby-msgpack gem存储32位浮点数?

发布时间:2020-12-17 03:25:28 所属栏目:百科 来源:网络整理
导读:我正在研究一个需要存储大量简单,可扩展数据的数据系统(以及我们在内部开发的一些专业索引,而不是这个问题的一部分).我希望存储数十亿条记录,因此高效的序列化是系统的关键部分.序列化需要快速,节省空间,并且支持多种平台和语言(因为打包和解包这些数据将是
我正在研究一个需要存储大量简单,可扩展数据的数据系统(以及我们在内部开发的一些专业索引,而不是这个问题的一部分).我希望存储数十亿条记录,因此高效的序列化是系统的关键部分.序列化需要快速,节省空间,并且支持多种平台和语言(因为打包和解包这些数据将是客户端组件的责任,而不是存储系统的一部分)

数据类型实际上是具有可选键/值对的散列.键将是小整数(在应用程序层解释).值可以是各种简单数据类型 – String,Integer,Float.

作为一种技术选择,我们选择了MessagePack,我正在编写代码来通过Ruby的msgpack-ruby gem进行数据序列化.

我不需要Ruby的64位Float的精度.即使对于32位的限制,存储的数字也没有任何有意义的精度.所以我想使用MessagePack支持32位浮点值.这肯定存在.但是,Ruby在任何64位系统上的默认行为是将Float序列化为64位:

MessagePack.pack(10.3)
 => "xCB@$x99x99x99x99x99x9A"

看看MessagePack代码,似乎有一个方法MessagePack::Packer#write_float32,这就是我所期望的:

MessagePack::DefaultFactory.packer.write_float32(10.3).to_s
 => "xCAA$xCCxCD"

. . .但我找不到设置默认打包器或创建新打包器的方法,在序列化更大的结构时将使用此方法.

作为对我的理解的考验,我尝试了这个:

class Float
  def to_msgpack_ext
    packer.write_float32(self)
  end

  def self.from_msgpack_ext s
    unpacker.read(s)
  end
end

MessagePack::DefaultFactory.register_type(0,Float )

MessagePack.pack(10.3)
 => "xCB@$x99x99x99x99x99x9A"

没有任何区别. . .很明显,我对MessagePack中使用的对象模型缺失或误解.我想做什么,我需要做什么?

解决方法

我知道使用MessagePack.pack会很好,但Ruby shim非常薄.它几乎没有为您提供进入C(或Java)库的入口点.正如AnoE指出的那样,我认为你只能为注册类型定制to_msgpack_ext和self.from_msgpack_ext,而不是内置类型.

您尝试的另一个问题是您无法从这些方法访问打包程序和解包程序.我想,你必须使用Array#pack和String#unpack,即使你能找到一种方法让你的库调用你的方法.要获得打包程序的句柄,您必须覆盖不同的方法:

class Float
  private
  def to_msgpack_with_packer(packer)
    packer.write_float32 self
    packer
  end
end

然后适当地调用它(参见this code为什么):

10.3.to_msgpack(MessagePack::Packer.new).to_s # => "xCAA$xCCxCD"

但是,当你在一个包含float的Hash上调用#to_msgpack时,这就会崩溃;它只是恢复其内部方法来打包哈希键和值.这就是为什么我在上面说过Ruby shim只给你一个入口点:核心扩展只用于初始调用.

我认为最好,最简单的解决方案是编写一个小的序列化函数,迭代Ruby中的哈希值,使用MessagePack::Packer API在看到浮点数时做你想做的事情等等.零C-hacking,零猴子修补,零混淆有人试图在六个月内阅读你的代码.

def pack_float32(obj,packer=MessagePack::Packer.new)
  case obj
  when Hash
    packer.write_map_header(obj.size)
    obj.each_pair do |key,value|
      pack_float32(value,pack_float32(key,packer))
    end
  when Enumerable
    packer.write_array_header(obj.size)
    obj.each do |value|
      pack_float32(value,packer)
    end
  when Float
    packer.write_float32(obj)
  else
    packer.write(obj)
  end

  packer
end

pack_float32(1=>[10.3]).to_s # => "x81x01x91xCAA$xCCxCD"

显然,这并没有经过严格测试,它可能无法处理所有边缘情况,但希望它足以让你开始.

另一个注意事项:您不必担心打开包装. msgpack-ruby似乎正确地将32位浮点数打包到64位浮点数,而我们没有任何摆弄.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读