通过从零开始构建一个简单的运行时来深入学习异步 Rustmichaelhelvey.dev/posts/rust_async_runtime-----------------------“如果你曾使用 Rust 构建过任何 Web 应用(或任何需要通过网络与其他服务通信的应用),那么你很可能已经接触过 async/await 语法。你也可能不得不安装一个异步运行时(极大概率是 tokio)。
大多数情况下,像 tokio 这样的库都能很好地“隐身”于幕后:你只需在 main 函数上加上一个 [tokio::main],并用 tokio::net::TcpListener 替代 std::net::TcpListener,你的服务器便神奇地能够使用仅少数几个线程处理成千上万的并发 TCP 连接。
但这背后究竟发生了什么?tokio 文档中的“深入异步”部分很好地解释了 Rust 标准库提供的各种异步 trait 和辅助结构体,以及 tokio 是如何实现它们的。阅读后,你会对执行器(executor)、任务(task)、唤醒器(waker)和未来对象(future)等概念有所了解。但在其示例中,你仍然只是启动一个线程休眠若干秒,然后使用另一个 crate 中的神奇 ArcWaker trait 来调度你的任务。
这些年来,我多次阅读过这些文档,也一直是异步 Rust 的满意用户。我读过大量文章,使用过许多库,编写过大量异步代码。但为了真正理解像 tokio 这类运行时背后的设计决策与权衡(例如,Send + 'static 的 future 确实令人烦恼——一个纯粹单线程的运行时会是什么样子?),我决定自己动手为 Rust 构建一个异步运行时,且不依赖任何外部库(好吧,严格来说有两个:我使用 rustix 来绑定所需的 POSIX API,当然还有标准 Rust 库)。它体积小、粗糙,可能在某些关键方面存在微妙的错误,除了教学用途外几乎毫无实用价值,但它让我对 Rust 的异步运行时有了深刻的理解。
在接下来的文章中,我将逐步讲解这个运行时的功能以及各个组件如何协同工作,并在最后分享我对整个实践过程的一些思考。”
