You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Future::poll()中正确使用sleep与wake?避免忙循环

解决Future::poll()中sleep导致忙循环的问题

你期望在Future::poll()中加入sleep避免忙循环,让Runtime每秒调用一次poll(),第5秒时返回Poll::Ready(()),但当前代码中cx.waker().wake_by_ref()会触发任务立即重新执行,导致CPU忙循环,输出大量"1"而非预期的5个。

问题根源

  1. 手动调用cx.waker().wake_by_ref()会直接唤醒任务,完全跳过了TokioSleep future的定时器等待逻辑,导致poll被无间断调用,形成忙循环。
  2. 现有Delay结构中的sleeper是固定的1秒sleep,没有在每次等待完成后重置,即使去掉手动唤醒,也只会等待一次1秒,后续poll无法触发新的定时等待。

修正方案

去掉手动唤醒逻辑,让Sleep future自行管理定时唤醒;同时每次sleeper完成等待后,重置它为新的1秒sleep,并输出"1",直到目标时间到达。

修正后的完整代码:

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use pin_project_lite::pin_project;
use std::time::{Duration, Instant};

pin_project! {
    struct Delay {
        when: Instant,
        #[pin]
        sleeper: tokio::time::Sleep,
    }
}

impl Delay {
    pub fn new(when: Instant) -> Self {
        Self {
            when,
            sleeper: tokio::time::sleep(Duration::from_secs(1))
        }
    }
}

impl Future for Delay {
    type Output = ();
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // 先检查是否到达目标时间
        if self.when < Instant::now() {
            return Poll::Ready(());
        }

        let mut this = self.project();

        // 检查当前sleeper是否完成
        match this.sleeper.as_mut().poll(cx) {
            Poll::Ready(()) => {
                // 1秒到了,输出"1"
                print!("1");
                // 重置sleeper为下一个1秒的sleep
                *this.sleeper = tokio::time::sleep(Duration::from_secs(1));
                // 返回Pending,等待下一次定时唤醒
                Poll::Pending
            }
            Poll::Pending => {
                // 还没到1秒,继续等待
                Poll::Pending
            }
        }
    }
}

#[tokio::main]
async fn main() {
    let when = Instant::now() + Duration::from_secs(5);
    let delay1 = Delay::new(when);
    delay1.await;
    println!("Hello, world!");
}

代码说明

  • 每次poll时先判断是否到达目标时间,到达则返回Poll::Ready(())结束future。
  • 若未到达目标时间,poll当前sleeper:如果返回Ready,说明1秒已过,输出"1"并重置sleeper为新的1秒定时;如果返回Pending,则让任务继续等待定时器唤醒。
  • 完全依赖Tokio的Sleep future管理定时唤醒,避免了手动唤醒导致的忙循环,同时保证每秒触发一次poll,输出一个"1",5秒后完成任务。

内容的提问来源于stack exchange,提问作者Anunaki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 04:05:26