【问题标题】:Is there any way to create a async stream generator that yields the result of repeatedly calling a function?有没有办法创建一个异步流生成器来产生重复调用函数的结果?
【发布时间】:2020-03-01 04:49:47
【问题描述】:

我想构建一个程序来收集天气更新并将它们表示为流。我想无限循环调用get_weather()finishstart之间有60秒的延迟。

简化版如下所示:

async fn get_weather() -> Weather { /* ... */ }

fn get_weather_stream() -> impl futures::Stream<Item = Weather> {
    loop {
        tokio::timer::delay_for(std::time::Duration::from_secs(60)).await;
        let weather = get_weather().await;
        yield weather; // This is not supported
        // Note: waiting for get_weather() stops the timer and avoids overflows.
    }
}

有什么方法可以轻松做到这一点?

get_weather() 花费超过 60 秒时,使用 tokio::timer::Interval 将不起作用:

fn get_weather_stream() -> impl futures::Stream<Item = Weather> {
    tokio::timer::Interval::new_with_delay(std::time::Duration::from_secs(60))
        .then(|| get_weather())
}

如果发生这种情况,下一个函数将立即启动。我想在前一个 get_weather() 开始和下一个 get_weather() 开始之间保持 60 秒。

【问题讨论】:

    标签: asynchronous rust async-await rust-tokio


    【解决方案1】:

    使用stream::unfold 从“期货世界”进入“流世界”。我们不需要任何额外的状态,所以我们使用空元组:

    use futures::StreamExt; // 0.3.4
    use std::time::Duration;
    use tokio::time; // 0.2.11
    
    struct Weather;
    
    async fn get_weather() -> Weather {
        Weather
    }
    
    const BETWEEN: Duration = Duration::from_secs(1);
    
    fn get_weather_stream() -> impl futures::Stream<Item = Weather> {
        futures::stream::unfold((), |_| async {
            time::delay_for(BETWEEN).await;
            let weather = get_weather().await;
            Some((weather, ()))
        })
    }
    
    #[tokio::main]
    async fn main() {
        get_weather_stream()
            .take(3)
            .for_each(|_v| async {
                println!("Got the weather");
            })
            .await;
    }
    
    % time ./target/debug/example
    
    Got the weather
    Got the weather
    Got the weather
    
    real    3.085   3085495us
    user    0.004   3928us
    sys     0.003   3151us
    

    另见:

    【讨论】:

    • 有没有办法允许通过引用将变量传递给get_weather()?我想在每次迭代中将它传递给get_weather_stream(),然后传递给get_weather()。当然,生成的 Stream 的生命周期应该取决于该变量。
    • @peku33 我不明白为什么它不起作用。也许您应该尝试一下并报告!
    • 在第一步中,我将&lt;'a&gt;(arg: &amp;'a i32) 添加到这两个函数中。我还将+ 'a 添加到get_weather_stream 返回。但是我得到closure may outlive current function。如果可能,我不想使用 Arc、Rc 等。
    • @peku33 seems to work
    猜你喜欢
    • 2019-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-20
    • 2021-12-30
    • 2016-04-14
    • 2020-08-18
    • 1970-01-01
    相关资源
    最近更新 更多