ToB企服应用市场:ToB评测及商务社交产业平台
标题:
Rust async 编程
[打印本页]
作者:
祗疼妳一个
时间:
2023-5-26 13:39
标题:
Rust async 编程
Rust async 编程
Asynchronous Programming in Rust:
https://rust-lang.github.io/async-book/
中文书名《Rust 异步编程指南》:
https://github.com/rustlang-cn/async-book
Rust语言圣经(Rust Course):
https://course.rs/advance/async/getting-started.html
一、
Getting Started
1.1 为什么使用 async
为什么使用 async
Async 编程,是一种并发(concurrent)编程模型
允许你在少数系统线程上运行大量的并发任务
通过 async/await 语法,看起来和同步编程差不多
其它的并发模型
OS 线程
无需改变任何编程模型,线程间同步困难,性能开销大
线程池可以降低一些成本,但难以支撑大量 IO 绑定的工作
Event-driven 编程
与回调函数一起用,可能高效
非线性的控制流,数据流和错误传播难以追踪
协程(Coroutines)
类似线程,无需改变编程模型
类似 async ,支持大量任务
抽象掉了底层细节(这对系统编程、自定义运行时的实现很重要)
Actor 模型
将所有并发计算划分为 actor , 消息通信易出错
可以有效的实现 actor 模型,但许多实际问题没解决(例如流程控制、重试逻辑)
Rust 中的 async
Future 是惰性的
只有poll时才能取得进展, 被丢弃的 future 就无法取得进展了
Async是零成本的
使用async ,可以无需堆内存分配(heap allocation)和动态调度(dynamic dispatch),对性能大好,且允许在受限环境使用 async
不提供内置运行时
运行时由Rust 社区提供,例如
tokio
单线程、多线程均支持
这两者拥有各自的优缺点
Rust 中的 async 和线程(thread)
OS 线程:
适用于少量任务,有内存和CPU开销,且线程生成和线程间切换非常昂贵
线程池可以降低一些成本
允许重用同步代码,代码无需大改,无需特定编程模型
有些系统支持修改线程优先级
Async:
显著降低内存和CPU开销
同等条件下,支持比线程多几个数量级的任务(少数线程支撑大量任务)
可执行文件大(需要生成状态机,每个可执行文件捆绑一个异步运行时)
Async 并不是比线程好,只是不同而已!
总结:
有大量 IO 任务需要并发运行时,选 async 模型
有部分 IO 任务需要并发运行时,选多线程,如果想要降低线程创建和销毁的开销,可以使用线程池
有大量 CPU 密集任务需要并行运行时,例如并行计算,选多线程模型,且让线程数等于或者稍大于 CPU 核心数
无所谓时,统一选多线程
例子
如果想并发的下载文件,你可以使用多线程如下实现:
fn get_two_sites() {
// Spawn two threads to do work. 创建两个新线程执行任务
let thread_one = thread::spawn(|| download("https://www.foo.com"));
let thread_two = thread::spawn(|| download("https://www.bar.com"));
// Wait for both threads to complete. 等待两个线程的完成
thread_one.join().expect("thread one panicked");
thread_two.join().expect("thread two panicked");
}
复制代码
使用async的方式:
async fn get_two_sites_async() {
// Create two different "futures" which, when run to completion, 创建两个不同的`future`,你可以把`future`理解为未来某个时刻会被执行的计划任务
// will asynchronously download the webpages. 当两个`future`被同时执行后,它们将并发的去下载目标页面
let future_one = download_async("https://www.foo.com");
let future_two = download_async("https://www.bar.com");
// Run both futures to completion at the same time. 同时运行两个`future`,直至完成
join!(future_one, future_two);
}
复制代码
自定义并发模型
除了线程和async,还可以用其它的并发模型(例如 event-driven)
1.2 Rust Async 的目前状态
Async Rust 目前的状态
部分稳定,部分仍在变化。
特点:
针对典型并发任务,性能出色
与高级语言特性频繁交互(生命周期、pinning)
同步和异步代码间、不同运行时的异步代码间存在兼容性约束
由于不断进化,维护负担更重
语言和库的支持
虽然Rust本身就支持Async编程,但很多应用依赖与社区的库:
标准库提供了最基本的特性、类型和功能,例如 Future trait
async/await 语法直接被Rust编译器支持
futures crate 提供了许多实用类型、宏和函数。它们可以用于任何异步应用程序。
异步代码、IO 和任务生成的执行由 "async runtimes" 提供,例如 Tokio 和 async-std。大多数async 应用程序和一些 async crate 都依赖于特定的运行时。
注意
Rust 不允许你在 trait 里声明 async 函数
编译和调试
编译错误:
由于 async 通常依赖于更复杂的语言功能,例如生命周期和Pinning,因此可能会更频繁地遇到这些类型的错误。
运行时错误:
每当运行时遇到异步函数,编译器会在后台生成一个状态机,Stack traces 里有其明细,以及运行时调用的函数。因此解释起来更复杂。
新的失效模式:
可能出现一些新的故障,它们可以通过编译,甚至单元测试。
兼容性考虑
async和同步代码不能总是自由组合
例如,不能直接从同步函数来调用 async 异步函数
Async 代码间也不总是能自由组合
一些crate依赖于特定的 async 运行时
因此,尽早研究确定使用哪个 async 运行时
性能特征
async 的性能依赖于运行时的表现(通常较出色)
1.3 async/await 入门
async
async 把一段代码转化为一个实现了Future trait 的状态机
虽然在同步方法中调用阻塞函数会阻塞整个线程,但阻塞的Future将放弃对线程的控制,从而允许其它Future来运行。
[code]~/rust via
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4