1个不稳定版本

0.1.0 2022年11月20日

#972 in 异步


用于 paxakos

MIT 许可证

45KB
935 代码行

snarc

Snarc提供了一种可发送的非原子引用计数智能指针。

crates.io docs.rs MIT licensed

工作原理

为了同时实现可发送性和非原子引用计数,必须做出权衡。这些权衡如下。

  • 只有一个强/拥有引用和任意多个弱引用。通过调用强/拥有引用的enter方法,其值可以临时绑定到当前线程。

  • 弱引用只能在与强/拥有引用的enter上下文中创建和丢弃。这确保了所需的计数器增量和减量是竞争自由的。

  • 在强引用的enter上下文中调用弱引用的get方法返回一个Option<&T>,即如果从强引用的enter上下文中调用,则为Some(&t)

它有什么好处?

snarc实现所启发的用例非常特殊。它看起来像以下这样。

// We have an async task.
let task = async {
    // This task is creating and executing subtasks.
    let subtasks = FuturesUnordered::new();

    // `x.method()` is returning 'static Futures that share mutable state
    subtasks.push(x.method());
    subtasks.push(x.method());

    // Somewhere within the same task, the subtasks are executed.
    subtasks.for_each(|x| async { /* ... */ });
};

由于x.method()返回的未来共享可变状态,因此该状态必须被包装在RefCell中。由于未来也有'static生命周期,因此该RefCell必须被引用计数智能指针包装。

替代方案

根据上述问题说明,这里有一些替代解决方案。

最终还是使用&RefCell<T>

这并不是真正解决问题的方案,但也许你可以放宽要求?也许你不需要返回的未来拥有 'static 生命周期?

优点

  • 无开销/最大效率

缺点

  • task 将是 !Send
  • 解决不同的问题

使用 Rc<RefCell<T>>

优点

  • 高度高效,有轻微的引用计数开销

缺点

  • task 将是 !Send

使用 Arc<Mutex<T>>

优点

  • task 将是 Send
  • 高度人体工程学
  • 子任务甚至可以变成自己的任务并在不同的线程上执行

缺点

  • 由于锁定开销而不高效

使用 Snarc<RefCell<T>SnarcRef<RefCell<T>>

优点

  • 高度高效,有轻微的引用计数开销
  • task 可以是 Send

缺点

  • 人体工程学效果不佳

许可: MIT

依赖

~34KB