rkyvRust 的零拷贝反序列化框架
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 还支持上下文序列化、反序列化和验证。它可以正确地序列化和反序列化共享指针,如Rc
和Arc
,并且可以扩展以支持自定义上下文类型。
最后,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);