#unique-id #thread-safe #id #unique-identifier #counter #static #ruid

highroller

一个简单、高级的线程安全滚动索引,保证低成本的运行时唯一ID

1 个不稳定版本

0.1.0 2024年6月23日

#436并发

MIT 许可证

34KB
587

highroller

GitHub Stars Crates.io Total Downloads GitHub Issues Current Version

一个简单、高级的线程安全滚动索引,保证低成本的运行时唯一ID。

用法

此 Rust 包提供了一个静态可用的、线程安全的滚动索引。适用于 UUID 过于复杂而需要低成本替代方案的场景。

提供的主要函数是 rolling_idx()。简单来说

let id1 = highroller::rolling_idx();
let id2 = highroller::rolling_idx();
println!("Id 1 is: {}", id1);
println!("Id 2 is: {}", id2);
// outputs:
// Id 1 is: 0
// Id 2 is: 1

函数 rolling_idx() 返回当前索引值。检索后,索引值增加 1。这样,每次调用此函数时,您都会得到一个唯一、不断增长的滚动索引。

请注意,滚动索引是运行时特定的,并且每次您的应用程序启动时都会重置。

滚动索引也是线程安全的,这意味着您可以从多个线程同时访问它,而不会遇到与并发数据访问相关的问题。

*待更多稳健的测试,应该成立。

特性标志

highroller 提供了几个特性标志以提高灵活性。

特性标志 默认 描述
strict 启用 在溢出时引发恐慌并禁用 RUID - 数字类型比较和
算术。 (当禁用时,溢出将回绕)
ruid_type 禁用 启用滚动唯一 ID (RUID) 类型,它是对滚动索引的包装
allow_arithmetics 禁用 可选支持对 RUID 执行算术运算 (请注意,如果不启用 strict,您应该知道自己在做什么,因为它可能导致模糊的行为)
size (单独的标志) u16_index 选择滚动索引的大小:u8_indexu16_indexu32_indexu64_indexu128_indexusize_index

如果您需要特定的滚动索引大小,或者您想使用 RUID 实现更明确的类型,请根据您的用例启用相应的特性。strict 特性可以帮助您捕获溢出,而 allow_arithmetics 标志扩展了 RUID 的功能,以支持算术运算。

RUID

“滚动唯一标识符”(RUID)本质上是对滚动索引的包装,支持可选的算术运算,以及完整的等价关系方法和显示方法。您可以使用 ruid_type 功能标志来启用 RUID 并将其用于您的程序。有关 RUID 的更多信息,请参阅“附加信息”部分

示例

考虑一个基本游戏,其中您召唤数字战士。每个召唤的战士都需要有一个唯一的标识符。为每个战士创建复杂的 UUID 可能会消耗宝贵的资源,并导致游戏性能问题。

这就是您可以利用 highroller 来分配唯一标识符的地方。它简单且高效

use std::sync::{Arc, Mutex};
use std::thread;
use rand::Rng;

struct Fighter {
  id: u8,
  power: u32,
};

// create a register for fighters
let fighters_register = Arc::new(Mutex::new(Vec::new()));

// create four threads as four different arenas
let arenas = 4;

// first, gather a randomized set of 20 fighters (power randomized) for each arena
let mut handlers = Vec::new();
for _ in 0..arenas {
  let fighters_register = Arc::clone(&fighters_register);
  handlers.push(thread::spawn(move || {
    let mut rng = rand::thread_rng();
    let mut ids = Vec::new();
    for _ in 0..20 {
      let fighter = Fighter {
        id: highroller::rolling_idx(),
        power: rng.gen_range(1, 100),
      };
      ids.push(fighter.id);
      fighters_register.lock().unwrap().push(fighter);
    }
    ids
  }));
}

// do a simple tournament that reveals a champion for each arena
let mut champions: Vec<Fighter> = Vec::with_capacity(arenas);
for handler in handlers {
  let arena_fighters = handler.join().unwrap();
  let fighters = fighters_register.lock().unwrap();
  
  // Find the fighter with the highest power in each arena
  let champion = arena_fighters.iter()
    .map(|&id| fighters.iter().find(|fighter| fighter.id == id).unwrap())
    .max_by_key(|fighter| fighter.power)
    .unwrap()
    .clone();
  
  champions.push(champion);
}

// now match the top against each other in a playoff that is based 
// on the power we randomized earlier
let ultimate_champion = champions.into_iter()
  .max_by_key(|fighter| fighter.power)
  .unwrap();

// print the winner by id
println!("The ultimate champion is fighter with id: {}", ultimate_champion.id);

在这个例子中,我们创建的每个战士都从 highroller::rolling_idx() 获取一个唯一的标识符。由于滚动索引是递增的,因此每个战士都会得到一个唯一的 ID。这不需要任何复杂的 UUID 或类似的开销,并且实用。

请记住,每次应用程序重新启动时,索引都会重置。如果您需要在应用程序重启之间保持持久性,您将需要实现额外的策略。

问题

有时,您需要一个非常简单的保证唯一标识符。使用 UUID 可能过于复杂,并带来您可能不需要承担的资源成本,如果您的用例非常简单且范围不大。

这时就出现了静态滚动计数器。

概念很简单:拥有一个静态可用的滚动值,该值在每次提取后自动递增。添加一些线程安全性措施,您就拥有了一个非常易于使用且保证唯一的标识符。

主要适用于简单的标识需求,它避免了许多复杂性,并且可以非常便宜地运行。

附加信息

使用 ruid_type 功能标志,您可以将 RUID(滚动唯一标识符)用作自定义整数类型。您可以将 RUID 转换为标准整数或反之,比较两个 RUID,如果 allow_arithmetics 标志开启,则可以使用算术运算来操作 RUID,并且由于它们实现了 fmt::Display 特性,因此可以打印 RUID

RUID 的使用示例

use highroller::RUID;

let id1 = RUID::new();
let id2 = RUID::new();

assert_ne!(id1, id2);

支持

无论您是否使用此项目、从中学习到知识还是只是喜欢它,请考虑通过购买我一杯咖啡来支持它,这样我就可以投入更多时间从事此类开源项目:)

Buy Me A Coffee

许可协议

您可以在 此处 查看完整的许可协议

本项目根据 MIT 许可协议授权。

依赖项

~10KB