为何Future::select会优先返回延迟更长的Future?技术问询
我懂你的困惑!当初我第一次摸Future::select的时候也踩过类似的坑,明明理论上它应该返回第一个完成的Future,结果看的示例里居然是延迟更长的先返回,完全和认知冲突,这大概率是你看的示例藏了容易忽略的细节,或者你对代码的逻辑理解有偏差。
先把
Future::select的核心逻辑掰明白 先给你吃个定心丸:select的设计目标就是同时驱动多个Future,谁先完成就先返回谁,超时机制就是靠这个逻辑实现的——比如把业务请求Future和一个固定延迟的超时Future绑在一起select,超时先完成就触发超时处理,业务请求先完成就正常处理结果。
那为什么会出现“延迟更长的Future被优先返回”的情况?大概率是这几种原因:
- 示例里用了阻塞式的延迟(比如
std::thread::sleep)而不是异步延迟,卡住了整个异步Runtime,导致短延迟的Future根本没机会被调度执行; - 示例里的延迟参数写反了,或者你误解了代码里的延迟定义;
- 短延迟的Future内部有阻塞逻辑,导致它实际完成时间反而比长延迟的更晚。
给你写个实打实的正确示例
拿Rust的tokio异步框架(大部分异步场景都会用它)举例,我们写两个延迟不同的Future,用select处理,你一看就懂:
use tokio::time::{sleep, Duration}; use futures::future::select; #[tokio::main] async fn main() { // 100ms后完成的短延迟Future let short_fut = sleep(Duration::from_millis(100)); // 500ms后完成的长延迟Future let long_fut = sleep(Duration::from_millis(500)); // 用select等待第一个完成的Future let result = select(short_fut, long_fut).await; match result { // 短延迟先完成,必然走进这个分支 futures::future::Either::Left((_, remaining_long_fut)) => { println!("短延迟Future先搞定了!"); // 要是需要的话,可以继续等待剩下的长延迟Future完成 remaining_long_fut.await; println!("剩下的长延迟Future也完成啦"); } // 理论上不会走到这里,除非代码逻辑出问题 futures::future::Either::Right((_, remaining_short_fut)) => { println!("这不对啊!长延迟怎么先完成了?"); remaining_short_fut.await; } } }
这段代码跑起来,肯定会先打印“短延迟Future先搞定了!”,等大概400ms后(因为长延迟已经跑了100ms),再打印后面的内容。
实现“先处理短延迟,再做后续”的正确姿势
如果你的需求是先处理第一个完成的(也就是短延迟的),再处理剩下的任务,就像上面示例那样:select返回的结果会包含已完成Future的输出和未完成的剩余Future,你可以把剩余的Future继续await,或者放到其他异步逻辑里处理。
要是你有多个Future需要处理,用select_all的逻辑也类似:它会返回第一个完成的Future的索引、输出,以及剩下的Future列表,你可以继续对剩下的列表做后续操作。
内容的提问来源于stack exchange,提问作者Sergey
相关产品推荐
相关产品推荐

