直接回答:Rust 的 Future 是惰性的,drop 一个 Future 就是取消它——这在 select! 分支竞争、timeout 包装时随时发生。取消安全指一个 Future 被中途 drop 后,系统状态仍然正确。反例经典场景:异步读取一行数据,已读了一半进缓冲区时被取消,缓冲区里的半条数据随之丢失,下次读就错位了。
展开解析:tokio 文档对常用 API 标注了 cancellation safety:channel 的 recv() 是安全的(消息没被取走就还在队列里),而很多带内部缓冲的读取操作不安全。应对策略:把“读出来”和“处理”拆成两步,先完整 recv 再进 select 分支处理;或使用 tokio_util::sync::CancellationToken 显式协调取消,让任务在安全的检查点收尾。自己写 Future 时要意识到:poll 返回 Pending 后任何时刻都可能被 drop,已修改的外部状态要么可回滚要么用 RAII guard 在 Drop 时清理。另一个关联坑:select! 的循环里构造的临时 Future 每轮重建,状态会丢,需要把 Future 拎到循环外(如 tokio::pin!)保持跨轮状态。理解这一点的元模型:取消不是异常,没有栈展开式的通知,全靠类型与文档约定。
追问方向:select! 的 biased 模式是什么?如何测试一个 Future 的取消安全性?
(约 470 字)