Android程序员初学Rust-通道

Rust 通道由两部分组成:Sender<T>Receiver<T>。这两部分通过通道相互连接,但你只能看到端点:

Rust 复制代码
use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel();

    tx.send(10).unwrap();
    tx.send(20).unwrap();

    println!("Received: {:?}", rx.recv());
    println!("Received: {:?}", rx.recv());

    let tx2 = tx.clone();
    tx2.send(30).unwrap();
    println!("Received: {:?}", rx.recv());
}

// Output
// Received: Ok(10)
// Received: Ok(20)
// Received: Ok(30)

mpsc 代表多生产者、单消费者(Multi-Producer, Single-Consumer),想象一下我们的电脑屏幕,很多设备信号都可以放到屏幕上显示,但是屏幕只有一个。SenderSyncSender 实现了 Clone(这样你就可以创建多个生产者),但 Receiver 没有实现。

send()recv() 方法返回 Result。如果返回 Err,这意味着对应的 SenderReceiver 已被丢弃,并且通道已关闭。

通过 mpsc::channel(),你可以创建一个无界且异步的通道(unbounded channel):

Rust 复制代码
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let thread_id = thread::current().id();
        for i in 0..10 {
            tx.send(format!("Message {i}")).unwrap();
            println!("{thread_id:?}: sent Message {i}");
        }
        println!("{thread_id:?}: done");
    });
    thread::sleep(Duration::from_millis(100));

    for msg in rx.iter() {
        println!("Main: got {msg}");
    }
}

输出如下:

makefile 复制代码
// Output
ThreadId(2): sent Message 0
ThreadId(2): sent Message 1
ThreadId(2): sent Message 2
ThreadId(2): sent Message 3
ThreadId(2): sent Message 4
ThreadId(2): sent Message 5
ThreadId(2): sent Message 6
ThreadId(2): sent Message 7
ThreadId(2): sent Message 8
ThreadId(2): sent Message 9
ThreadId(2): done
Main: got Message 0
Main: got Message 1
Main: got Message 2
Main: got Message 3
Main: got Message 4
Main: got Message 5
Main: got Message 6
Main: got Message 7
Main: got Message 8
Main: got Message 9

如果要在多线程的情况下发送消息呢?

Rust 复制代码
fn main() {
    let (tx, rx) = mpsc::channel();
    
    // 注意这里的写法,多使用了一对大括号,在最后返回的闭包。
    thread::spawn({
        let tx = tx.clone();
        move || {
            for i in 0..10 {
                tx.send(i).unwrap();
            }
        }
    });

    thread::spawn(move || {
        for i in 10..20 {
            tx.send(i).unwrap();
        }
    });

    for i in rx {
        println!("received {}", i);
    }
}

tx 的所有权被释放的时候,通道也就关闭了。所以,你可以尝试一下,如果在第二个线程的地方,也使用类似克隆的方式,你会发现,最后这个 for 循环,会一直阻塞。

一个无界通道会根据存储待处理消息的需要分配足够的空间。send() 方法不会阻塞调用线程。

如果通道已关闭,调用 send() 方法将终止并返回一个错误(这就是它返回 Result 的原因)。当接收器被释放时,通道就会关闭。

对于有界(同步)通道(bounded channel),send() 可能会阻塞当前线程:

Rust 复制代码
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    let (tx, rx) = mpsc::sync_channel(3);

    thread::spawn(move || {
        let thread_id = thread::current().id();
        for i in 0..10 {
            tx.send(format!("Message {i}")).unwrap();
            println!("{thread_id:?}: sent Message {i}");
        }
        println!("{thread_id:?}: done");
    });
    thread::sleep(Duration::from_millis(100));

    for msg in rx.iter() {
        println!("Main: got {msg}");
    }
}

调用 send() 会阻塞当前线程,直到通道中有空间来存放新消息。如果没有人从通道中读取消息,线程可能会无限期阻塞。

与无界通道一样,如果通道已关闭,调用 send() 会因错误而中止。

大小为零的有界通道称为"会合通道"。每次调用 send() 都会阻塞当前线程,直到另一个线程调用 recv()

相关推荐
小马爱打代码7 分钟前
Spring Boot内嵌容器深度解析:Tomcat是如何被启动的?
spring boot·后端·tomcat
小江的记录本10 分钟前
【反射】Java反射 全方位知识体系(附 应用场景 + 《八股文常考面试题》)
java·开发语言·前端·后端·python·spring·面试
孟陬10 分钟前
国外技术周刊 #4:这38条阅读法则改变了我的人生、男人似乎只追求四件事……
前端·人工智能·后端
无心水15 分钟前
【时间利器】5、多语言时间处理实战:Go/C#/Rust/Ruby统一规范
golang·rust·c#·时间·分布式架构·openclaw·openclaw变现
Source.Liu16 分钟前
【Rust】Rust 项目结构详解
rust
没有bug.的程序员17 分钟前
100%采样率引发的全线熔断:Spring Boot 链路追踪的性能绞杀与物理级调优
java·spring boot·后端·生产·熔断·调优·链路追踪
无籽西瓜a21 分钟前
Linux 文件权限与 chmod 详解
linux·服务器·后端
thulium_37 分钟前
Rust 编译错误:link.exe 未找到
开发语言·后端·rust
SimonKing40 分钟前
IntelliJ IDEA 配置与插件全部迁移到其他盘,彻底释放C盘空间
java·后端·程序员
华科易迅42 分钟前
Spring 代理
java·后端·spring