陈天 · Rust 编程第一课
陈天
Tubi TV 研发副总裁
23195 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 65 讲
基础篇 (21讲)
陈天 · Rust 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

34|并发处理(下):从atomics到Channel,Rust都提供了什么工具?

思考题
Actor
通讯
同步
原语
并发处理

该思维导图由 AI 生成,仅供参考

你好,我是陈天。
对于并发状态下这三种常见的工作模式:自由竞争模式、map/reduce 模式、DAG 模式,我们的难点是如何在这些并发的任务中进行同步。atomic / Mutex 解决了自由竞争模式下并发任务的同步问题,也能够很好地解决 map/reduce 模式下的同步问题,因为此时同步只发生在 map 和 reduce 两个阶段。
然而,它们没有解决一个更高层次的问题,也就是 DAG 模式:如果这种访问需要按照一定顺序进行或者前后有依赖关系,该怎么做?
这个问题的典型场景是生产者 - 消费者模式:生产者生产出来内容后,需要有机制通知消费者可以消费比如 socket 上有数据了,通知处理线程来处理数据,处理完成之后,再通知 socket 收发的线程发送数据。

Condvar

所以,操作系统还提供了 Condvar。Condvar 有两种状态:
等待(wait):线程在队列中等待,直到满足某个条件。
通知(notify):当 condvar 的条件满足时,当前线程通知其他等待的线程可以被唤醒。通知可以是单个通知,也可以是多个通知,甚至广播(通知所有人)。
在实践中,Condvar 往往和 Mutex 一起使用:Mutex 用于保证条件在读写时互斥,Condvar 用于控制线程的等待和唤醒。我们来看一个例子:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Rust提供了丰富的并发处理工具,包括atomics、Mutex、Condvar和各种类型的Channel,以及Actor模型的实现。这些工具可以帮助开发者处理并发任务之间的通讯和同步,实现“无畏并发”。文章介绍了这些工具的使用场景和特点,以及如何利用它们解决不同的并发问题。通过示例代码展示了如何使用Condvar实现线程间通信和同步,以及利用Channel处理复杂的DAG并发模式。此外,文章还强调了Rust提供的多样化并发原语的重要性,以及在实际应用中灵活选择合适的工具的必要性。总体而言,Rust为开发者提供了丰富的并发处理工具,使并发编程变得更加简单和灵活。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《陈天 · Rust 编程第一课》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(14)

  • 最新
  • 精选
  • ×22
    请问一下,目前rust的标准库中并没有类似concurrent hash map等并发安全的集合,虽然第三方库有一些实现,但是不容易从中做出选择,请问老师有什么推荐吗

    作者回复: dashmap,如果你的使用场景适合的话,也可以尝试 Jon 写的 left-right: https://github.com/jonhoo/left-right

    2021-12-17
    3
  • 核桃
    Channel 把锁封装在了队列写入和读取的小块区域内,然后把读者和写者完全分离,使得读者读取数据和写者写入数据,对开发者而言,除了潜在的上下文切换外,完全和锁无关,就像访问一个本地队列一样 这段文字,我还是没有很明白,所谓对于channel和mutex锁的区别,是不是可以这样理解?channel可以看成是一个队列(vec那样的),然后channel这里就是一头写入一头消费,那么如果有并发的时候,就是对头尾进行加锁,并且会做多一些其他的辅助操作,例如队列满了或者空的时候各种安全检查判断等等,实际上channel就是对mutex+queue的抽象封装? 多谢了

    作者回复: 对,高级的并发原语都是低级的原语的组合和做了精心的使用限制。我文中有讲到什么样的 channel 大概用了什么样的技术去实现。比如 mpsc,因为 consumer 只有一个,所以实现地好的话 consumer 侧不需要锁。

    2021-12-05
    2
  • newzai
    go经常会使用 chan struct 来作为actor对象的退出信号,rust有什么建议不?不想和数据channel混合在一起。

    作者回复: 你可以使用单独的 channel,也可以用 condvar,也可以用第三方封装好的 signal。

    2021-11-16
    1
  • 千回百转无劫山
    读完本节有一个感悟,actor model是异步任务级别的“微服务”:发送信息给一个actor,然后从actor再接收信息,就类似于后端中发送一个请求给一个微服务,再接收响应。也就是说,一个actor对应一个“”微服务“”,不知道这种理解是否正确?还有就是,一个actor对应的是类似于tokio的一个task吗?

    作者回复: 理解正确

    2021-11-16
  • 罗杰
    对,合理的使用 Channel,不应该死搬硬套。

    作者回复: 👍

    2021-11-15
  • GengTeng
    笨拙地用 Channel 叠加 Channel 来应对所有的场景?Go: 你直接说我名儿得了。

    作者回复: 哈哈

    2021-11-15
    2
  • 朱叶子
    工作线程中,缺了drop(started),导致主线程无法获取mutex
    2022-06-24
    4
  • Geek_e188ed
    老师,代码示例有点少啊,比如Channel这块,你的文字描述我都看懂了,但是没有使用Channel的代码示例,可能怎么调用我都不知道
    2022-07-10
    1
    2
  • 终生恻隐
    #[test] fn test_mpsc() { let (a2btx, a2brx) = mpsc::channel(); let (b2atx, b2arx) = mpsc::channel(); let threada = thread::spawn(move || { a2btx.send("hello world!".to_string()).unwrap(); for re in b2arx { println!("{}\n", re); thread::sleep(Duration::from_secs(1)); a2btx.send("hello world!".to_string()).unwrap(); } }); let threadb = thread::spawn(move || { for re in a2brx { println!("{}\n", re); thread::sleep(Duration::from_secs(1)); b2atx.send("goodbye!".to_string()).unwrap(); } }); thread::sleep(Duration::from_secs(10)); return }
    2021-11-15
    1
  • Rex Wang
    Mutex使用lock方法生成Guard锁住数据,而Guard通过drop方法才能把数据解锁。老师的例子化用了doc中的例子,但因为没有对变量 started 显式使用drop方法,而使用loop阻塞了 started 自动调用drop,所以和预设的结果表现不同。
    2023-09-08归属地:北京
收起评论
显示
设置
留言
14
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部