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

15|tokio编程:在多任务之间操作同一片数据

你好,我是 Mike。今天我们一起来学习如何在 tokio 的多个任务之间共享同一片数据。
并发任务之间如何共享数据是一个非常重要的课题,在所有语言中都会碰到。不同的语言提供的方案支持不尽相同,比如 Erlang 语言默认只提供消息模型,Golang 也推荐使用 channel 来在并发任务之间进行同步。
Rust 语言考虑到其应用领域的广泛性和多样性,提供了多种机制来达到这一目的,需要我们根据不同的场景自行选择最合适的机制。所以相对来说,Rust 在这方面要学的知识点要多一些,好处是它在几乎所有场景中都能做到最好。

任务目标

定义一个内存数据库 db,在不同的子任务中,并发地向这个内存数据库更新数据。

潜在问题

为了简化问题,我们把 Vec<u32> 当作 db。比如这个 db 中现在有 10 个数据。
let mut db: Vec<u32> = vec![1,2,3,4,5,6,7,8,9,10];
现在有两个任务 task_a 和 task_b,它们都想更新 db 里的第 5 个元素的数据 db[4]。
task_a 想把它更新成 50,task_b 想把它更新成 100。这两个任务之间是没有协同机制的,也就是互相不知道对方的存在,更不知道对方要干嘛。于是就可能出现这样的情况,两个任务几乎同时发起更新请求,假如 task_a 领先一点点时间,先把 db[4] 更新成 50 了,但是它得校验一下更新正确了没有,所以它得发起一个索引请求,把 db[4] 的数据取出来看看是不是 50。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Rust语言中使用tokio编程时,多任务之间共享数据的问题及解决方案是本文的主要内容。文章首先强调了并发任务之间共享数据的重要性,并讨论了可能出现的问题,如数据竞争和系统紊乱。作者提出了解决方案,包括全局变量和在main函数中创建对象实例传递给各个任务。然而,全局变量不适合多任务并发程序,应尽可能避免使用。文章介绍了在Rust中使用Arc智能指针和Mutex来实现多任务共享数据的方法。通过具体示例和讨论,展示了在tokio编程中如何处理多任务共享数据的问题,以及Rust语言提供的多种机制来解决这一问题。文章还介绍了RwLock和std::sync::atomic等其他锁的使用方法。总体而言,本文深入浅出,适合读者快速了解tokio编程中的并发数据共享问题及解决方案。文章通过验证的方式,展示了在Rust和tokio中如何在多个任务中操作共享数据,强调了Rust所有权模型在并发场景下的重要作用。整个探索过程虽然辛苦,但结果却是美好的,体现了Rust的学习过程。

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

全部留言(19)

  • 最新
  • 精选
  • lilp
    1. 应该是防止这两个任务还没走完,主线程就结束了? 2. 不会阻塞。我理解的是这两个任务 同时启动,顺序完成。不管他俩怎么去抢这个锁 最后的完成顺序应该还是和main中写的.await() 顺序一样。

    作者回复: 1 是的。 2 spawn后就立即执行。后面这两句只是等待任务返回。在执行第二句之前有可能第二个任务已经执行完了,第二句只是把其任务的返回值取回来。

    2023-11-23归属地:广东
    2
    4
  • PEtFiSh
    await代码会持续等待直到任务结束,因此在main thread里第一行会阻塞第二行。但这不会让task_a阻塞task_b。加入await可以使最后的println!打印两个任务执行完以后被修改的db值,如果不加入await。有一定几率最后println!打印的还是原始的db

    作者回复: 👍

    2023-11-23归属地:上海
    2
  • -
    有个疑问,Arc::new(Mutex::new(db))后可以将一个不可变的变量变成可变变量?这个是什么原因

    作者回复: 思考得很棒,前后联系起来了。arc mutex 其实是拿到了对象所有权,有所有权了当然修改值就方便了。跟前面并不冲突,当然如果还想深入下去,可以看看 内部可变性 这个概念。

    2023-11-22归属地:北京
    3
    2
  • seven9t
    可以说下如果用rust自带的Mutex而不是tokio的会有什么问题 (是否必须配套

    作者回复: 关于这个话题,可以看下tokio官网的一个说明:https://tokio.rs/tokio/tutorial/shared-state 区别就是要不要跨 await 边界。

    2024-01-14归属地:广东
    1
  • yunyi
    1、为了等待任务完成 2、不会阻塞,两个任务是并行运行的,结果也有可能是被改成50,taskb先完成,再执行taska。

    作者回复: 👍

    2024-01-12归属地:广东
    1
  • 下雨天
    看实现,就当前例子而言task_a不会阻塞task_b。 如果task_a中loop{}下就可以阻塞了。 有个疑问,为啥task::spawn后面会自动执行呢? 我理解只有.await了才会加到调度器里面执行。

    作者回复: spawn比较特殊,特殊处理的

    2023-11-23归属地:湖北
    3
    1
  • Geek_72807e
    请问老师,方案四中,会不会出现两次修改操作顺序不确定的问题,最终结构可以是40,也会是100?

    作者回复: 很棒的思考👍,有可能出现。看哪个任务后执行完成,后抢到锁。

    2023-11-22归属地:山西
    2
    1
  • 雍和
    会,因为要获取mutex

    作者回复: 不会,你执行就知道了。原因在下一讲有讲。

    2023-11-22归属地:广东
    1
  • Geek_3b58b9
    对原子变量的读写访问可以用指针?还是说应该用专门的API?我记得原子类型有特定的CPU指令的

    作者回复: 智能指针不是传统意义上的c那种指针。 锁的实现就需要用到指令集层面的原子指令来优化。

    2024-01-15归属地:江苏
  • yunyi
    哇 ,居然看到了Erlang的字眼,我一直是用erlang做为主力语言的后端开发,最近在学rust,找了很多资料,最后买了老师的教程,如获至宝

    作者回复: 幸会幸会

    2024-01-12归属地:广东
收起评论
显示
设置
留言
19
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部