2个版本

0.1.2 2023年3月22日
0.1.1 2022年4月13日
0.1.0 2022年4月13日

#1242 in 异步

MIT/Apache

93KB
1.5K SLoC

unsync

github crates.io docs.rs build status

异步Rust的解同步同步原语。

该包提供了一组相对简单的同步原语,它们明确标记为 !Send!Sync。这使得它们适用于单线程系统,如 yew

您可以将此视为现在已废弃的 futures::unsync 模块的现代替代品。


为什么需要 !Send / !Sync 同步原语?

由于它们主要用于线程间跨任务通信,因此无同步同步原语可能看起来有些 奇怪

随着像 yew 这样的单线程系统逐渐成熟并获得了更丰富的异步编程支持,对这些原语的需求也随之增加。为了使它们尽可能高效,它们在无同步系统和约束的考虑下编写,这样它们就不必使用原子操作和锁。

由于通道在典型应用程序中扮演的角色以及它们针对无竞争使用进行了优化,因此真实系统中的同步开销应很小。但无同步代码仍然能够针对性能和大小进行更好的优化。

在我的一个应用程序中,用 tokio::sync::oneshot 替换为 unsync::oneshot 后,生成的二进制文件大小减少了30KB(优化后减少10KB,使用 wasm-opt)。此项目中的合成基准测试表明,当在 LocalSet 中使用时,优化的构建中unsync通道的速度大约是twice。

我没有深入探讨为什么会出现这种情况,但只要这种情况存在,我就希望有人能够访问这些即插即用的替代品,以利用这些好处。


用法

将以下内容添加到您的 Cargo.toml

unsync = "0.1.1"

示例

use unsync::spsc::{channel, Sender, Receiver};
use std::error::Error;
use tokio::task;

async fn receiver(mut rx: Receiver<u32>) -> Vec<u32> {
    let mut out = Vec::new();

    while let Some(m) = rx.recv().await {
        out.push(m);
    }

    out
}

async fn sender(mut tx: Sender<u32>) -> Result<(), Box<dyn Error>> {
    for n in 0..1000 {
        tx.send(n).await?;
    }

    Ok(())
}

async fn run() -> Result<(), Box<dyn Error>> {
    let (tx, rx) = channel(4);

    let _ = task::spawn_local(sender(tx));
    let out = task::spawn_local(receiver(rx)).await?;

    let expected = (0..1000).collect::<Vec<u32>>();
    assert_eq!(out, expected);
    Ok(())
}

依赖项

~45KB