4 个稳定版本
1.1.1 | 2023年9月21日 |
---|---|
1.1.0 | 2022年12月12日 |
1.0.1 | 2023年9月21日 |
1.0.0 | 2022年7月19日 |
#290 在 并发
每月 22 次下载
在 second-music-system 中使用
19KB
168 代码行
arcow
此 crate 提供了一个线程安全的、引用计数的指针,它使用写时复制语义来实现可变性。
我创建它是因为我不知道从 2015 年开始在标准 Rust 中就有的 Arc::make_mut
方法。我考虑过废弃它以支持标准解决方案,但有一些微小的优势可以勉强证明它是合理的
Arcow
比标准库中的Arc::make_mut
更易于使用。(从缺点来说,更容易意外通过Arcow
进行突变。)Arcow
不支持弱引用,这使得它在运行时效率更高。
如何
创建一个 Arcow<T>
。这就像一个可以廉价克隆的 T
,可以像普通对象一样进行修改,即使 T
实际上克隆成本很高。你可以自由地将 Arcow<T>
的克隆发送到多个线程。
请注意,原子操作不是免费的;这就是为什么 Arcow
没有实现 Copy
。只有当以下条件满足时,克隆 Arcow<T>
并将其发送到另一个线程才会比克隆 T
更便宜:
T
很大(克隆成本高),并且Arcow<T>
的克隆中有相当一部分将在不进行突变的情况下被使用和消费。
为什么不
如果可能的话,您应该考虑使用 Cow<T>
。如果您想要将突变传播到对同一底层 T
的其他引用,那么您根本不需要写时复制,您实际上想要做的是在 Mutex<T>
的包装中。
原因呢?
假设您正在实现一个游戏服务器。您跟踪多个游戏状态迭代,可能有很多,以允许保存、客户端预测和其他问题。您的大部分游戏状态都很简单,因此每个迭代只有一个单独的副本。但是,您的游戏发生在 Map
上,而这个 Map
通常大约有 64KiB。在总体规模上,这并不多,但它会迅速增加,将地图复制到每个新迭代的开销浪费了大量的 CPU 时间。您的自动测试尤其受到影响,因为它们几乎所有的空闲时间都在复制,而不是真正测试您的逻辑。
因此,您将 Map
包装在一个 Arc
中。现在,您已经用一个单一的原子操作替换了 64KiB 的副本。您拍拍自己的背,然后继续前进。
但问题是 Map
可以改变。
在绝大多数迭代中,Map
不会改变。但有时,有人会砍倒一棵树,或者建造一堵墙,或者铺路,当这样做时,这些更改将反映在 Map
中。如果您移除 Arc
,这没有问题,因为每个迭代都有自己的地图副本来突变。但现在,您在每个迭代中都要复制整个 64KiB,尽管不到 1% 的迭代会随后突变地图。
Cow
对于这种情况不起作用,因为没有长期存在的“主副本”的地图,所有其他游戏状态都可以从中借用。没有特定的迭代可以信任这一点。旧迭代将随着它们不再相关而被修剪,新的迭代也不一定保留(例如,废弃的预测时间线)。
每当有变化时都克隆 Arc<Map>
是一个可行的解决方案,但如果有两个玩家在同一个时间单位砍倒一棵树怎么办?这是一个浪费的副本。然后还有这种情况,您是单玩家模式中客户端的内部服务器,只有一个相关的迭代...现在,每次更改都会复制 Map
,尽管根本不超过一个引用!
因此,Arcow
。它非常像一个简化的 Arc
,但有一个额外的特性:它可以被突变。一个有生命的引用计数指针要么是唯一的,要么是共享的。如果您有一个唯一的 Arcow
,突变很简单。 DerefMut
将返回对内部类型的可变引用。只要这个可变引用存在,您就不能再克隆 Arcow
,因此唯一性得到保持。如果您有一个共享的 Arcow
,DerefMut
将首先将您的 Arcow
“分割”成原始共享值的唯一克隆,然后您就设置好了。
(*并不完全准确。你可以克隆当前可变借用的一个 Arcow
,但你之后不能再通过这个借用进行修改。查看:)
# use arcow::Arcow;
// error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
let mut a = Arcow::new(456);
let borrowed = &mut *a;
// - mutable borrow occurs here
*borrowed = 42;
let b = a.clone();
// ^^^^^^^^^ immutable borrow occurs here
*borrowed = 47;
// --------- mutable borrow later used here
法律条款
Arcow 版权所有 2022, 2023 Solra Bizna,并许可以下任一:
- Apache 许可协议,版本 2.0 (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可协议 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选其一。
除非你明确声明,否则任何你有意提交以包含在 Arcow 库中的贡献,如 Apache-2.0 许可协议中定义的,应按上述方式双重许可,不附加任何额外条款或条件。