Rust 异步 IO
要运行异步 Rust 代码,您需要一个异步运行时。 但是,目前,选择运行时会将您锁定在生态系统的一个子集中。 库 crate 和工具通常仅限于特定的运行时; 改变运行时间很困难。 混合和匹配来自不同运行时生态系统的库需要运行多个执行器并使用不完美的兼容层。 对于开始使用异步 Rust 的程序员来说,寻找和选择运行时是摩擦的根源。
异步相比线程开销小,bug 没那么复杂
Future 类似 js 的 Promise,返回 impl Future
// 基于 poll(状态机,通知 Future 来取值) 而不是 callback(把值传过去),方便取消(?)
async fn foo(arg: &str) -> usize { ... }
// fn foo<'a>(arg: &'a str) -> impl Future
还引入了 Pin 用来解决一些引用问题 // 不可移动的对象可以在它们的字段之间存储指针(?)
需要一个执行者来执行 Future // 如 futures crate
使用系统的 io 回调来检查 Future 是否完成
mio 提供的唯二两个核心功能分别是: // 类似 libuv,轮询 epoll
- 对操作系统异步网络 IO 的封装
- Linux(Android) => epoll
- Windows => iocp
- MacOS(iOS), FreeBSD => kqueue
- Fuchsia => port
- 用户自定义事件队列
// epoll 维护一个活动列表(想象成发生了变化的 fd 事件集,链结构),只需要遍历这个列表,而不需要遍历所有
// 使用系统提供的 epoll 可以减少内核态-用户态切换
// 内核收到数据,设置 fd ,标记状态
`expression.await`
// 并发方案还有绿色线程,Actor 模型?(线程池)
Rust’s approach to async I/O are:
- Minimize system resources for handling a large number of concurrent I/O tasks
- Provide a zero-cost abstraction on top of the async I/O mechanisms provided by operating systems
- Do it at a library level, instead of introducing a runtime to Rust
Instead of doing the silly wasteful thing, the futures crate is far smarter. It has a mechanism to:
- determine which task is trying to get access to the data provided by this future, and then
- notify that task that new data is available
A Future is an action with a delayed single result. A Stream is a stream of results, like an Iterator, with a delay between each value.
Stream 有一个 for_each 用来执行函数,返回一个 Future(future::ok(())) 可以让 tokio::run
// js 的 Stream 也是生成多个 Promise
What if we want to process each directory concurrently? To do that, we need to spawn another task, the same way we would spawn a new thread. Like tokio::run, tokio::spawn takes a Future where both Item and Error are ().
// 一个任务有 future poll 顺序,多个任务可以一次 poll 多个 future
// The default executor is usually a thread pool.