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()

相关推荐
百锦再2 分钟前
第14章 智能指针
android·java·开发语言·git·rust·go·错误
倚栏听风雨37 分钟前
git "base点"详解,顺便解释merge和rebase区别
后端
掘金一周1 小时前
重新思考 weapp-tailwindcss 的未来 | 掘金一周 11.13
前端·人工智能·后端
小生凡一1 小时前
图解|Go语言实现 Agent|LLM+MCP+RAG
开发语言·后端·golang
l0sgAi1 小时前
SpringAI 整合MCP实现联网搜索 (基于tavily)
java·后端
朝新_1 小时前
【统一功能处理】从入门到源码:拦截器学习指南(含适配器模式深度解读)
数据库·后端·mybatis·适配器模式·javaee
q***7481 小时前
私有化部署DeepSeek并SpringBoot集成使用(附UI界面使用教程-支持语音、图片)
spring boot·后端·ui
John_Rey1 小时前
API 设计哲学:构建健壮、易用且符合惯用语的 Rust 库
网络·算法·rust
勤奋的小小尘1 小时前
第六篇: Rust 中的"静态方法"(关联函数)
rust
勤奋的小小尘1 小时前
第七篇: Rust 多线程与并发编程详解
rust