rust 异步:如何在循环中使用select(no_std环境)保持相同的future?

nx7onnlm  于 2022-12-04  发布在  其他
关注(0)|答案(1)|浏览(112)

我有两个异步函数:get_message和get_event。我希望在消息到达或事件发生时执行一个操作,并在无限循环中永远执行该操作。
简化的设置如下所示:

use futures::{future::select, future::Either, pin_mut};

impl MsgReceiver {
    async fn get_message(&mut self) -> Message { /* ... */ }
}

impl EventListener {
    async fn get_event(&mut self) -> Event { /* ... */ }
}

async fn eternal_task(receiver: MsgReceiver, listener: EventListener) -> ! {
    let get_msg_fut = receiver.get_message();
    pin_mut!(get_msg_fut);
    loop {
        let get_event_fut = listener.get_event();

        pin_mut!(get_event_fut);

        match select(get_event_fut, get_msg_fut).await {
            Either::Left((ev, r_get_msg_fut)) => {
                /* react to the event */

                // r_get_msg_fut is not done, how to reuse it in the next iteration?
            }
            Either::Right((msg, r_get_event_fut)) => {
                /* react to the message */

                // it's fine to drop get_event_fut here

                // the following line causes a double-mut-borrow error on receiver,
                // despite receiver isn't borrowed anymore (the old future is completed and dropped)
                let new_future = receiver.get_message();
            }
        };
    }
}

我在这里有三个主要问题:
1.当一个事件首先出现时,如何告诉rust我想在下一次循环迭代中重用不完整的get_message future?
1.当一个信息首先出现时,如何构造一个没有借位错误的新未来?
1.当(2)被解决时,如何将新的future放入相同的固定内存位置,并在下一次循环迭代中使用它?

3htmauhk

3htmauhk1#

我已经成功地使用了这个,但是无法摆脱Box::pin

use futures::{future::select, future::Either, pin_mut};
use std::sync::Mutex;
#[derive(Debug)]
struct MsgReceiver;
#[derive(Debug)]
struct EventListener;
#[derive(Debug)]
struct Message;
#[derive(Debug)]
struct Event;
impl MsgReceiver {
    async fn get_message(&mut self) -> Message {
        Message
    }
}

impl EventListener {
    async fn get_event(&mut self) -> Event { 
        Event
    }

}

async fn eternal_task(receiver: MsgReceiver, mut listener: EventListener) -> ! {
    let receiver = Mutex::new(receiver);
    let mut f = None;
    loop {
        let get_msg_fut = match f.take() {
            None => {
                let mut l = receiver.lock();
                Box::pin(async move {
                    l.get_message().await
                })
            }
            Some(f) => f,

        };
        let get_event_fut = listener.get_event();
        pin_mut!(get_event_fut);

        match select(get_event_fut, get_msg_fut).await {
            Either::Left((ev, r_get_msg_fut)) => {
                /* react to the event */
                // store the future for next iteration
                f = Some(r_get_msg_fut);
            }
            Either::Right((msg, r_get_event_fut)) => {
                /* react to the message */
            }
        };
    }
}

#[tokio::main]
async fn main() {
    eternal_task(MsgReceiver, EventListener).await;
}

相关问题