当前位置: 首页 > news >正文

Rust 异步中的 Waker

Rust语言圣经中关于 Waker 的描述是很不完整的,导致新手不可能从中看懂 Waker 在实际应用中真正的工作方式。本文旨在对这部分内容做一个补充,帮助新手了解 “Rust 异步生态是如何基于 Rust 编译器提供的能力建立的” 。

如果你读了圣经,还不清楚 Rust 中 async/.await 的工作原理,不知道编译器在其中做了什么,不知道执行器是用来 poll Future 的,可以去读读Rust 异步编程基础这篇。但这篇中没有提到 Waker 的作用。

还有我特别推荐一个开源仓库hexagonal-sun/trale: Tiny Rust Async Linux Executor,是一个难得的兼具简单易懂和符合实际情况两种特性的 Rust 异步执行器的实现。你对 Rust 异步底层有什么问题,都可以去看看,不费太大功夫,很可能能解答你的问题!

Waker 基础概念

因为 Rust 异步中和 Waker 相关相似的概念比较多,容易混淆,所以先罗列梳理一下

有一个 Trait 叫 Wake,它有一个方法叫 wake

impl Wake for TaskId {fn wake(self: Arc<TaskId>) {EXEC.with(|exec| {let mut exec = exec.borrow_mut();if let Some(task) = exec.waiting.try_remove(self.0.load(Ordering::Relaxed)) {exec.run_q.push(task);}});}
}

有一个结构体叫 Waker,Waker 有一个 from 方法,可以利用 Impl Wake 的对象生成 Waker。Waker 还有一个 wake 方法,wake 方法内部其实在调用用于生成 Waker 的 Impl Wake 对象的 wake 方法。

let waker = Waker::from(task.id.clone());waker.wake();

有一个结构体叫 Context,Context 有一个 from_waker 方法,从 Waker 的引用中生成 Context。Context 有一个 waker() 方法,用于获取用于生成 Context 的 Waker 的引用。

let waker = Waker::from(task.id.clone());let mut cx = Context::from_waker(&waker);cx.waker();

是不是真挺绕的。

异步库、执行器和 Waker

回顾一下关于 async/.await、Future 和 执行器的知识。Future 是标准库定义的一个 trait,有一个 poll 方法。async 指定的代码块会被编译器编译成一个 Future,代码块执行的逻辑被编译器处理后(形成一个状态机)放到 poll 方法里。.await 只能在 async 中使用,通过 .await 调用其他 async 块或 Future,编译器把 .await 转化为对 Future 的 poll,所以编译器生成的 Future poll 中,外层 Future 的 poll 内部会 poll 内层的 Future,直至最内一层的 Future。最外层的 async 或者 Future 会被放入执行器,执行器负责不断 poll Future,直至其返回完成的状态 

重点:poll 方法有一个参数 Context,执行器在 poll 最外层 Future 时会传入一个 Context。这个 Context 是编写执行器代码的人通过上面的 from_waker 之类的方法构造的。最外层的 Future 的 poll 方法内部有编译器生成的 poll 内层 Future 的代码,poll 内层 Future 时,会把这个 Context 传下去,传到最底层的 Future。最底层的 Future 是编写执行器的人手工实现的(不是编译器通过 async/.await 生成的),其 poll 方法内部会利用 Context 找到 Waker。这个最底层 Future 一般用于调用阻塞或者异步的系统 IO,比如 send/recv,如果 IO 不能立即响应,此 Future 会让执行器等待 IO 响应(通过 OS 提供的功能比如 epoll,io_uring),并将 Waker 注册给执行器,再向外层返回 Pending,通过返回值,执行器得知 Future 没有完成。执行器在没有 Future 可 poll 的时候就等待 OS(epoll, io_uring)的反馈,得到阻塞或异步的 IO 可以继续推进的响应后,就找到此 IO 对应的 Waker(由刚刚的底层 Future 注册),调用 Waker.wake() 将外层 Future 重新放回执行器的待 poll 队列中。这里的 Waker.wake 也是编写执行器的人负责实现的。到此,执行器才能异步地调度上层用户随意实现的 Future。

引用自 hexagonal-sun/trale: Tiny Rust Async Linux Executor

圣经只告诉我们 Waker.wake() 告知 执行器 Future 可以继续执行,没有告诉我们这是如何做到的。实际上,只有底层 Future,Waker,Executor 三者利用 OS 协同工作,才能做到上文中的:1. 底层 Future 告知 Executor 等待特定事件,并将 Waker 与事件绑定注册给 Executor;2. Executor 知道从哪里等待 IO 事件的更新,从哪里获取 Future 注册的 Waker;3. Waker.wake() 能将 Future 重新交给 Executor。之所以他们能完成这么复杂的协同,是因为底层 Future,Waker,Executor 都是同一伙人编写的,(目前为止)并非协商好特定接口就能做到的。

这就引出一个额外的问题,我们使用的上层异步库,比如LinkBond in rtnetlink - Rust,这种顶层 async 或 Future 也是编 Executor 那帮人实现的吗?并非如此,第三方的人也可以自行实现上层异步库,不过你必须要选择一个 Executor 作为你的执行器,并用该 Executor 提供的底层异步 IO Future。反过来,如果你用了一个 Executor 的底层异步 IO Future,你就不能用其他 Executor 作为你的执行器了!

有一篇博客 Portable and interoperable async Rust 证实了上述理论:

讨论

在最初使用 Rust 异步库时,我以为随意挑选一个执行器即可,但想不明白在这种情况下 Waker 是怎么工作的,异步库实现的 Future 怎么知道如何将 Waker 注册给执行器,在它甚至不知道用哪个执行器的情况下?在我了解到实际情况后,感叹道,原来 Rust 中一个执行器就代表一个异步生态,而执行器就是异步生态的核心。编写执行器需要负责的内容要比想象的多。当时觉得是不是这种上层库和执行器的绑定太不灵活了,怪不得Portable and interoperable async Rust这篇博客呼吁搞一个统一的执行器让上下层分离。但转念一想,比如 C++ 的 Boost.asio 也是一个异步库,干脆同时实现了上层接口和底层执行器,根本没想把执行器这个概念单拎出来,所以 Rust 虽然可能做的还不够,但做的也不少了。

http://www.lryc.cn/news/624993.html

相关文章:

  • PMP-项目管理-十大知识领域:资源管理-管理团队、设备、材料等资源
  • OpenCV Python——Numpy基本操作(Numpy 矩阵操作、Numpy 矩阵的检索与赋值、Numpy 操作ROI)
  • 3D检测笔记:基础坐标系与标注框介绍
  • JAiRouter 架构揭秘:一个面向 AI 时代的响应式网关设计
  • JUC读写锁
  • 宁波市第八届网络安全大赛初赛(REVERSE-Writeup)
  • 基于Spring Boot+Vue的社区便民服务平台 智慧社区平台 志愿者服务管理
  • day25|学习前端js
  • Product Hunt 每日热榜 | 2025-08-18
  • 【yocto】为什么要选择yocto?
  • 亚马逊新手突围:从流量破冰到持续出单
  • Less (CSS 预处理器)
  • 问答社区运营优化:cpolar 提升 Answer 平台远程访问速度方案
  • 性能测试(Jemter)
  • day44_2025-08-18
  • PMP-项目管理-十大知识领域:风险管理-识别、评估、应对项目风险
  • 兴趣爱好——虾哥开源小智AI机器人搭建(丐版—最低成本)ESP32开发板 MicroPython V1.0.0 Rev1
  • 继承中的向上转型、向下转型与动态绑定的深入解析
  • 学习游戏制作记录(各种独特物品效果)8.18
  • 【Langchain系列二】LangChain+Prompt +LLM智能问答入门
  • Prompt engineering(PE) —— prompt 优化如何进行?
  • 集成电路学习:什么是Face Detection人脸检测
  • leetcode4_452 and 763
  • 【论文学习】UoMo: 一个用于无线网络优化的移动流量预测通用模型
  • 学习嵌入式的第二十天——数据结构
  • 如何解决机器翻译的“幻觉“问题(Hallucination)?
  • 特赞内容运营解决方案,AI重构品牌内容价值链
  • (Arxiv-2025)OPENS2V-NEXUS:一个面向主体到视频生成的详细基准与百万规模数据集
  • 知识蒸馏 - 各类概率分布
  • 概率论基础教程第4章 随机变量(三)