#string-interning #interning #string #cache #perfect-hash

interned-string

高性能且适用于通用目的的并发字符串缓存

3 个版本 (破坏性更新)

0.3.0 2024 年 7 月 6 日
0.2.0 2024 年 7 月 4 日
0.1.0 2024 年 7 月 4 日

#76缓存

Download history 166/week @ 2024-06-29 145/week @ 2024-07-06 6/week @ 2024-07-13 35/week @ 2024-07-27

每月 248 次下载

MPL-2.0 许可证

36KB
625

interned-string

此存储库公开 IString,一种不可变且已缓存的字符串类型。

它为高性能和考虑多线程而构建。

它提供了 O(1) 的 HashEq 操作,非常适合您的 HashMap<IString, _>

入门指南

您可以通过调用 intern() 来缓存任何 String&str 值。

您可以将 IString 通过引用传递给任何接受 &str 的函数。

use interned_string::Intern;

fn main() {
    let my_istring = "hello".intern();

    foo(&my_istring);
}

fn foo(string: &str) {
    println!("{string}");
}

如果您启用了 serde 功能,您可以在您的 DTO 中使用 IString 代替 String

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
interned-string = { version = "0.1", features = ["serde"] }
use serde::Deserialize;
use interned_string::IString;

#[derive(Deserialize, Debug)]
struct ExampleDTO {
    favorite_dish: IString
}

fn main() {
    let serialized = "{\"favorite_dish\":\"pasta\"}";

    let example: ExampleDTO = serde_json::from_str(&serialized).unwrap();

    println!("{example:?}")
    // ExampleDTO { favorite_dish: IString("pasta") }
}

性能特点

读取 IString 的内容非常快,无锁且无等待(归功于 left_right)。IString 可以在任意数量的线程中共享和读取。它可以随着读取线程数量的线性增长而扩展。

代价是创建一个新的 IString 会更慢。需要遍历基数树(紧凑前缀树)以去重新字符串,需要获取锁,如果字符串尚未缓存,则需要更新树。虽然可以从多个线程并行执行树遍历,但锁阻止了写入的线性扩展。

计划改进

  • 用可重用字符串存储的基数树或重新编写它,而不是在基数树中存储每个已缓存字符串的副本。目前,由于这个原因,存储库使用了 2 倍的已缓存字符串存储空间(1 倍在存储中,1 倍作为基数树中的副本)。

  • 在后台/冷路径中释放未使用字符串的内存。目前内存仅在存储中插入新字符串时才会释放,这可能会令人意外。

贡献

欢迎您提交PR。任何贡献都将被高度赞赏。

如果您有建议,请提交Issue。

许可

Mozilla Public License 2.0

致谢

特别感谢Jon Gjengset (@jonhoo) 为此crate提供灵感,以及他对 left-right 的工作。

依赖

~0.8–27MB
~343K SLoC