rkyvRust 的零拷贝反序列化框架

联合创作 · 2023-09-28 09:40

rkyv 是一个用于 rust 的零拷贝反序列化框架。

它类似于其他零拷贝反序列化框架,例如 Cap'n Proto 和 FlatBuffers。然而,前者具有外部模式和严格限制的数据类型,而 rkyv 允许在代码中定义所有序列化类型,并且可以序列化其他类型无法序列化的各种类型。此外,rkyv 被设计为几乎没有开销,并且在大多数情况下将执行与本机类型完全相同的操作。

与 serde 一样,rkyv 使用 Rust 强大的特征系统来序列化数据而无需反射。尽管具有广泛的功能,但你也只需为使用的功能付费。如果你的数据检出,序列化过程可以像memcpy一样简单。与 serde 一样,这允许 rkyv 以类似于手写序列化程序的速度执行。

与 serde 不同,rkyv 生成的数据保证没有反序列化。如果你将数据写入磁盘,你只需将文件mmap​​​​​​写入内存,投射一个指针,你的数据就可以使用了。这使其成为高性能和 IO 密集型应用程序的理想选择。

通过 Pin API 支持有限的数据突变,如果需要完整的突变功能,归档的值可以通过 Deserialize 真正反序列化。

rkyv 有一个 hashmap 实现,它是为零拷贝反序列化而构建的,所以你可以随意序列化你的 hashmaps。该实现使用压缩、散列和置换算法执行完美散列,以使用尽可能少的内存,同时仍然执行快速查找。

它还带有 B+ 树实现,该实现通过将数据拆分为易于分页的 4KB 段来实现最佳性能。这使得它非常适合为批量数据构建不可变的数据库和结构。

rkyv 还支持上下文序列化、反序列化和验证。它可以正确地序列化和反序列化共享指针,如RcArc,并且可以扩展以支持自定义上下文类型。

最后,rkyv 使得序列化 trait 对象成为可能,并且无需反序列化就可以将它们用作 trait 对象更多细节见archive_dyn crate。

虽然 rkyv 是最终数据的一种很好的格式,但它缺乏完整的模式系统,并且不能很好地进行数据迁移和模式升级。如果你的用例需要这些功能,可能需要额外的库来在 rkyv 之上构建这些功能。可以使用与 rkyv 相同类型的其他序列化框架,如 serde,无冲突。

示例

use rkyv::{Archive, Deserialize, Serialize};
// bytecheck can be used to validate your data if you want
use bytecheck::CheckBytes;

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
// This will generate a PartialEq impl between our unarchived and archived types
#[archive(compare(PartialEq))]
// To use the safe API, you have to derive CheckBytes for the archived type
#[archive_attr(derive(CheckBytes, Debug))]
struct Test {
    int: u8,
    string: String,
    option: Option<Vec<i32>>,
}

let value = Test {
    int: 42,
    string: "hello world".to_string(),
    option: Some(vec![1, 2, 3, 4]),
};

// Serializing is as easy as a single function call
let bytes = rkyv::to_bytes::<_, 256>(&value).unwrap();

// Or you can customize your serialization for better performance
// and compatibility with #![no_std] environments
use rkyv::ser::{Serializer, serializers::AllocSerializer};

let mut serializer = AllocSerializer::<0>::default();
serializer.serialize_value(&value).unwrap();
let bytes = serializer.into_serializer().into_inner();

// You can use the safe API for fast zero-copy deserialization
let archived = rkyv::check_archived_root::<Test>(&bytes[..]).unwrap();
assert_eq!(archived, &value);

// Or you can use the unsafe API for maximum performance
let archived = unsafe { rkyv::archived_root::<Test>(&bytes[..]) };
assert_eq!(archived, &value);

// And you can always deserialize back to the original type
let deserialized: Test = archived.deserialize(&mut rkyv::Infallible).unwrap();
assert_eq!(deserialized, value);
浏览 19
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报