Rust 语言从入门到实战
唐刚
Rust 语言中文社区联合创始人
5266 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 36 讲
Rust 语言从入门到实战
15
15
1.0x
00:00/00:00
登录|注册

16|tokio编程:使用channel在不同任务间通信?

你好,我是 Mike。今天我们来了解并发编程的另一种范式——使用 channel 在不同的任务间进行通信。
channel 翻译成中文就是通道或管道,用来在 task 之间传递消息。这个概念本身并不难。我们回忆一下上节课的目标:要在多个任务中同时对一个内存数据库进行更新。其实我们也可以用 channel 的思路来解决这个问题。
我们先来分解一下任务。
创建三个子任务,task_a、task_b 和另一个起代理作用的 task_c。
在 task_a 和 task_b 中,不直接操作 db 本身,而是向 task_c 发一个消息。
task_c 里面会拿到 db 的所有权,收到从 task_a 和 task_b 来的消息后,对 db 进行操作。
基于这个思路,我们来重写上一节课的示例。

MPSC Channel

我们使用 tokio 中的 MPSC Channel 来实现。MPSC Channel 是多生产者,单消费者通道(Multi-Producers Single Consumer)。
MPSC 的基本用法如下:
let (tx, mut rx) = mpsc::channel(100);
使用 MPSC 模块的 channel() 函数创建一个通道对,tx 表示发送端,rx 表示接收端,rx 前面要加 mut 修饰符,因为 rx 在接收数据的时候使用了可变借用。channel 使用的时候要给一个整数参数,表示这个通道容量多大。tokio 的这个 mpsc::channel 是带背压功能的,也就是说,如果发送端发得太快,接收端来不及消耗导致通道堵塞了的话,这个 channel 会让发送端阻塞等待,直到通道里面的数据包被消耗到留出空位为止。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了使用tokio中的channel进行并发编程的方法和技巧。通过使用MPSC Channel(多生产者,单消费者通道)实现了任务间的消息传递,并通过示例代码演示了如何利用代理模式处理消息。此外,文章还介绍了tokio中的其他channel类型,包括broadcast channel和watch channel,以及任务管理的两种常见模式。通过丰富的示例和详细的解释,读者可以快速了解并掌握并发编程的相关知识。文章还提供了思考题,鼓励读者留下自己的思考和疑问,以及分享给其他朋友。整体而言,本文对于想要深入了解并掌握并发编程的读者来说,是一篇非常有价值的文章。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Rust 语言从入门到实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(11)

  • 最新
  • 精选
  • Aaaaaaaaaaayou
    join 和 select 类似于 JavaScript 中的 Promise.all 和 Promise.race

    作者回复: 👍

    2024-01-26归属地:广东
    1
  • 刘丹
    请问老师: r = task_a => r.unwrap() 这是闭包,还是匿名函数?

    作者回复: 这是tokio那个宏里面的特殊语法,不是标准的rust语法。就是一个语法而已。既不是闭包,也不是匿名函数

    2023-11-24归属地:广东
    1
  • superggn
    背压 - back pressure 带背压的 channel tokio::mpsc::channel(n) std::mpsc::sync_channel(n) 不带背压的 channel tokio::mpsc::unbounded_channel(); std::mpsc::channel();

    作者回复: 👍

    2024-01-26归属地:北京
  • superggn
    思考题 - Arc::new(Mutex::new(target_var)); - res = join_handler.await.unwrap(); - channel

    作者回复: 棒棒哒

    2023-12-25归属地:北京
  • superggn
    捉虫: `等待所有任务一起返回` main 前面少个 fn

    作者回复: 哈哈,感谢指出,可能编辑的时候漏了。尽快处理

    2023-12-25归属地:北京
  • 刘永臣
    .await()类似于等待组吧? channel的四种模式也是go channel常用的四种场景。

    作者回复: await是单个任务。rust中waitgroup实现也很简单。四种模式对应起来了,可能tokio就是借鉴的go channel。

    2023-11-28归属地:北京
  • 学水
    如果通道都没有任何生产者消息,select语句中的消费者是堵塞在那里还是会之间进入下一个语句呢

    作者回复: rx.await就是在task层面阻塞住。

    2023-11-25归属地:加拿大
  • 老大
    为啥我按照你写的,运行不起来呢?

    作者回复: 你可以帖一下代码。

    2023-11-24归属地:河南
  • PEtFiSh
    从任务收集返回结果的方式有: 1、任务直接返回值,然后通过handler取回,比如:a = task_a.await.unwrap(); 2、通过锁的方式直接写在目标位置 3、通过channel的形式传递结果 4、似乎也可以unsafe来写全局变量。

    作者回复: 👍,很棒。mpsc 和 oneshot 都可以派上用场。

    2023-11-24归属地:上海
  • 伯阳
    这种无锁并发,快是快了点,但是如果给通道打满了,怎么处理呢

    作者回复: 打满了就阻塞了。打不进去了,就等吧,消耗一个就能打进去一个。

    2023-11-24归属地:北京
收起评论
显示
设置
留言
11
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部