专栏名称: 阿里云开发者
阿里巴巴官方技术号,关于阿里的技术创新均将呈现于此
目录
相关文章推荐
白鲸出海  ·  Habby之后,多个厂商“玩转”Roguel ... ·  18 小时前  
海外独角兽  ·  从 AI 招聘到数据标注,Mercor ... ·  20 小时前  
阿里云开发者  ·  一站式智能分析引擎,快速构建企业级数据分析 ... ·  22 小时前  
AIGC开放社区  ·  高通将以24亿美元收购Alphawave ... ·  昨天  
AIGC开放社区  ·  高通将以24亿美元收购Alphawave ... ·  昨天  
51好读  ›  专栏  ›  阿里云开发者

浅析 rust 大明星 Tokio

阿里云开发者  · 公众号  · 科技公司  · 2025-06-09 18:00

主要观点总结

本文介绍了Tokio框架的基本概念、架构和工作原理,包括其在Rust语言中的异步编程模型、任务调度和生命周期等。文章还对比了Tokio与Nginx的调度机制,并探讨了Tokio未来的发展方向,如IO Uring支持、扩展协议栈、日志与调试支持和内部调度算法更新等。此外,文章还涉及了Tokio在不同平台和形式的支持情况。

关键观点总结

关键观点1: Tokio框架简介


关键观点2: Tokio架构和工作原理


关键观点3: 与Nginx的调度对比


关键观点4: Tokio未来发展方向




正文

请到「今天看啥」查看全文


上述 Future trait中,poll 是核心方法,用于推进状态机的进行。我们的代码不会直接调用 poll,而是通过 Rust 的关键字 .await 来执行这个 Future,await 会被 rust 在编译时生成代码来调用 poll,返回 Poll(见下),如果是 Pending 则被 runtime 挂起(比如重新放到任务队列中)。当有 event 产生时,挂起的 future 会被唤醒,Rust 会再次调用 future 的 poll,如果此时返回 Ready 就执行完成。

pub enumPoll<T> {    Ready(T),    Pending,}

多级 Future 嵌套时,只有遇到类似 .await 才会推动执行,是协同式调度而不是抢占式调度(Tokio 1.x版本引入抢占机制来缓解饥饿问题,但rust原生基础是协同式调度)。因此 rust 无需提前为 Future 分配独立的栈或堆上内存,是一种零成本抽象。

总结

如下图所示,rust std 中的异步只维护 Future 以及内部方法 poll,具体的任务队列和调度方法由第三方的 runtime 来实现。每次代码执行到 .await 时会进行一次poll,poll 若 ready 则直接退出表示执行完成,poll 若遇到阻塞,则挂起等待事件池来唤醒。当有事件(例如I/O等)唤醒之后,会把该挂起 Future 封装为 task,加入到任务队列中等待调度,runtime 会不断地从任务队列中拿出任务来执行。

Tokio 架构与构造过程

架构

承接上文,这一部分主要介绍 Tokio 实现的 runtime架构,如下图所示:

  • Tokio 会启动很多 Worker,每个 Worker 对应一个线程,并发完成异步任务。Worker 内部又主要包括 任务队列 和 Driver引用。

  • Driver 是异步运行时中的“驱动引擎”,它通过操作系统提供的 I/O 多路复用机制(如 Linux 上的 epoll 、Windows 上的 IOCP 、macOS 上的 kqueue )来监听 I/O 事件和定时器事件,并在事件就绪后唤醒对应的 Future 继续执行。Tokio 中的 Driver 又分为I/O和Time,I/O负责监听socket和文件读写,Time负责sleep等定时任务。

  • Tokio 将 Future 封装为任务,其中主要包含了waker,waker挂载到 Driver 中,当 Driver 有新事件时会回调 waker 来停止阻塞,并加入到任务队列中。

  • 任务会加入到任务队列中,任务队列又分为每个 Worker 内部的,以及全局的队列。通常在 Worker 创建的任务即加入到内部队列,全局创造的加入到全局队列,全局队列的任务会被任何 Worker 线程执行到。

构造(build)

Tokio 中的 Runtime 结构体如下:

pub structRuntime {    /// Task scheduler    schedulerScheduler,
    /// Handle to runtime, also contains driver handles    handleHandle,
    /// Blocking pool handle, used to signal shutdown    blocking_poolBlockingPool,}

blocking线程 和 worker线程:worker线程是我们要重点关注的运行时轻量级线程,负责调度和任务执行;blocking线程是在这个过程中的所有的阻塞任务,其数量等于所有的worker线程数量+其他控制线程数量,原因是worker线程本身就是一个blocking任务,其他控制线程又包括信号与通道等。

其中 BlockingPool 是专门用来运行阻塞任务的线程池,上述解释已简单概括;Handle 维护了过程中各种handler,本文不重点关注这两项。Scheduler 是“任务池”和“调度器”的封装,也是 Runtime 最核心的部分。

想要使用 Runtime 必须要经过初始化:

tokio::runtime::Builder::new_multi_thread()                .enable_all().worker_threads(threads).thread_name(name)                .build().unwrap(),

build() 即构造了 Runtime 结构,其中最重要的是 Driver 和 Worker 。







请到「今天看啥」查看全文