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

Rust手动实现超时任务Future:编译修复与优化咨询

Rust异步任务超时控制问题解答

功能背景

存在一个异步任务,若10秒内收到信号则任务可继续执行,否则取消;若任务在10秒内已执行完成,则无需执行任何操作。

问题

  1. 以下代码存在编译问题,如何修复?
  2. 是否可以进行优化(ready状态实际被查询了两次)?
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::sync::mpsc::Receiver;
use std::time::Duration;

struct MyFuture {
    timeout: tokio::time::Timeout<Receiver<()>>,
    task: Box<dyn Future<Output = ()> + Unpin>,
    ready: Option<bool>,
}

impl MyFuture {
    fn new(
        receiver: Receiver<()>,
        duration: Duration,
        task: Box<dyn Future<Output = ()> + Unpin>,
    ) -> Self {
        let timeout = tokio::time::timeout(duration, receiver);
        Self {
            timeout,
            task,
            ready: None,
        }
    }
}

impl Future for MyFuture {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        match Pin::new(&mut self.task).poll(cx) {
            Poll::Ready(_) => Poll::Ready(()),
            Poll::Pending => match self.ready {
                Some(true) => Poll::Pending,
                Some(false) => Poll::Ready(()),
                // !!! compile error here
                None => match Pin::new(&mut self.timeout).poll(cx) {
                    Poll::Pending => Poll::Pending,
                    Poll::Ready(r) => {
                        if r.is_err() {
                            // timeout and cancel task
                            self.ready = Some(false);
                            Poll::Ready(())
                        } else {
                            // receive signal and wait task finished
                            self.ready = Some(true);
                            Poll::Pending
                        }
                    }
                },
            },
        }
    }
}

1. 编译错误修复

编译错误的核心原因是**match self.ready时转移了ready字段的所有权**,导致后续无法对self.ready赋值(所有权已被移走,self的可变引用处于无效状态)。

修复方法是使用引用模式匹配避免所有权转移:

// 将原match self.ready改为引用匹配
Poll::Pending => match &self.ready {
    Some(true) => Poll::Pending,
    Some(false) => Poll::Ready(()),
    None => {
        match Pin::new(&mut self.timeout).poll(cx) {
            Poll::Pending => Poll::Pending,
            Poll::Ready(r) => {
                if r.is_err() {
                    self.ready = Some(false);
                    Poll::Ready(())
                } else {
                    self.ready = Some(true);
                    Poll::Pending
                }
            }
        }
    }
},

也可以用as_ref()方法获取引用实现相同效果:

match self.ready.as_ref() {
    Some(true) => Poll::Pending,
    Some(false) => Poll::Ready(()),
    None => { /* 超时/信号处理逻辑 */ }
}

2. 代码优化(减少ready状态查询)

原代码存在逻辑冗余,每次poll都要先查任务状态再查ready。可以通过明确状态机枚举替代模糊的Option<bool>,同时调整执行顺序优化:

优化后代码

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::sync::mpsc::Receiver;
use std::time::Duration;

// 用枚举明确表示当前状态,替代Option<bool>
enum State {
    WaitingForSignalOrTimeout,
    WaitingForTask, // 已收到信号,等待任务完成
    Cancelled,      // 已超时,任务取消
}

struct MyFuture {
    timeout: tokio::time::Timeout<Receiver<()>>,
    task: Box<dyn Future<Output = ()> + Unpin>,
    state: State,
}

impl MyFuture {
    fn new(
        receiver: Receiver<()>,
        duration: Duration,
        task: Box<dyn Future<Output = ()> + Unpin>,
    ) -> Self {
        let timeout = tokio::time::timeout(duration, receiver);
        Self {
            timeout,
            task,
            state: State::WaitingForSignalOrTimeout,
        }
    }
}

impl Future for MyFuture {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // 先统一检查任务是否完成,无论当前状态
        if let Poll::Ready(_) = Pin::new(&mut self.task).poll(cx) {
            return Poll::Ready(());
        }

        // 根据当前状态处理逻辑
        match &mut self.state {
            State::Cancelled => Poll::Ready(()),
            State::WaitingForTask => Poll::Pending,
            State::WaitingForSignalOrTimeout => {
                match Pin::new(&mut self.timeout).poll(cx) {
                    Poll::Pending => Poll::Pending,
                    Poll::Ready(r) => {
                        if r.is_err() {
                            *self.state = State::Cancelled;
                            Poll::Ready(())
                        } else {
                            *self.state = State::WaitingForTask;
                            Poll::Pending
                        }
                    }
                }
            }
        }
    }
}

优化点说明

  1. 状态语义明确:用State枚举替代Option<bool>,避免模糊的true/false语义,代码可读性大幅提升;
  2. 减少冗余查询:先统一检查任务完成状态,再处理状态逻辑,避免原代码中重复查询ready的操作;
  3. 逻辑路径清晰:状态转移路径明确,后续维护和扩展更方便。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 19:06:09