#async-channel #channel #oneshot-channel #reusable #async #oneshot #future

multishot

一个异步、无锁、可重用的通道,用于向异步任务发送单个值

3个版本 (破坏性更新)

0.3.2 2024年3月20日
0.3.1 2024年3月19日
0.3.0 2022年12月29日
0.2.0 2022年2月14日
0.1.0 2022年2月10日

#173 in 异步

Download history 159/week @ 2024-04-23 112/week @ 2024-04-30 199/week @ 2024-05-07 218/week @ 2024-05-14 281/week @ 2024-05-21 175/week @ 2024-05-28 88/week @ 2024-06-04 62/week @ 2024-06-11 48/week @ 2024-06-18 120/week @ 2024-06-25 46/week @ 2024-07-02 19/week @ 2024-07-09 37/week @ 2024-07-16 71/week @ 2024-07-23 264/week @ 2024-07-30 132/week @ 2024-08-06

每月508次下载
用于asynchronix

MIT/Apache

53KB
678

multishot

一个异步、无锁、可重用的通道,用于向异步任务发送单个值。

Cargo Documentation License

概述

在多投通道中,接收方部分是可重用的,并且可以在不重新分配的情况下回收发送方部分。发送或等待值以及回收发送方都是无锁操作,后两个操作还是无等待的。如果先前发送者发送的值已被接收,则创建新的发送者不需要额外的同步或自旋:它保证立即成功。

用法

将此内容添加到您的 Cargo.toml

[dependencies]
multishot = "0.3.2"

示例

use std::thread;

async {
    let (s, mut r) = multishot::channel();

    // Send a value to the channel from another thread.
    thread::spawn(move || {
        s.send("42");
    });

    // Receive the value.
    let res = r.recv().await;
    assert_eq!(res, Ok("42"));

    // Recycle the sender. This is guaranteed to succeed if the previous
    // message has been read.
    let s = r.sender().unwrap();

    // Drop the sender on another thread without sending a message.
    thread::spawn(move || {
        drop(s);
    });

    // Receive an error.
    let res = r.recv().await;
    assert_eq!(res, Err(multishot::RecvError {}));
};

安全性

这是一个低级原语,因此其实现依赖于 unsafe。测试套件广泛使用 Loom 和 MIRI 来评估其正确性。尽管它们非常出色,但Loom和MIRI无法形式化证明不存在数据竞争,因此确实存在稳健性问题。

实现

发送、接收和回收发送者都是无锁操作;后两个操作还是无等待的。

如果值 readily available,轮询不需要读取-修改-写入(RMW)操作,如果这是第一次唤醒更新,则需要1 RMW,否则需要2 RMW。如果没有注册唤醒者,则发送需要1 RMW,如果已注册唤醒者,则通常需要2 RMW。与Tokio等不可重用的单次通道相比,唯一的额外成本是在实践中很少更新的唤醒者更新时的1 RMW。此外,multishot的实现通过在发送时使用算术原子操作而不是通常更昂贵的比较和交换操作来部分抵消这种额外成本。

许可证

此软件根据您的选择,在Apache许可证,版本2.0MIT许可证下授权。

贡献

除非您明确声明,否则根据Apache-2.0许可证定义,您提交的任何有意包含在工作中的贡献都将按照上述方式双重许可,而不附加任何额外条款或条件。

依赖项

~0–26MB
~329K SLoC