如何将向量处理为异步流?

时间:2019-12-08 17:19:15

标签: asynchronous rust async-await

在我的RSS reader project中,我想异步读取我的RSS feed。当前,由于this code block

可以同步读取它们
self.feeds = self
    .feeds
    .iter()
    .map(|f| f.read(&self.settings))
    .collect::<Vec<Feed>>();

我想使该代码异步,因为它将使我能够更好地处理不良的Web服务器响应。

我了解我可以使用Stream通过Vecstream::from_iter(...)创建的self.feeds = stream::from_iter(self.feeds.iter()) .map(|f| f.read(&self.settings)) // ??? .collect::<Vec<Feed>>() } ,它将代码转换为类似的内容

Vec

但是,我有两个问题

  1. 如何将结果加入task::spawn(这是一个同步结构)中?
  2. 如何执行该流?我当时正在考虑使用className={mystyle},但似乎不起作用...

1 个答案:

答案 0 :(得分:0)

  

如何执行该流?我当时在考虑使用task::spawn,但似乎不起作用

async/await世界中,异步代码是由执行者执行的,该执行者不是标准库的一部分,而是由诸如tokio之类的第三方包装箱提供的。 task::spawn仅调度async fn的一个实例运行,而不实际运行它。

  

如何将结果加入vec(这是一个同步结构)

您的RSS读者的面包和黄油似乎是f.read。它应该变成一个异步函数。然后将提要的向量映射到期货的向量中,需要对其进行轮询才能完成。

futures板条箱有futures::stream::futures_unordered::FuturesUnordered可以帮助您完成此操作。 FuturesUnordered本身实现了Stream特征。然后将此流收集到结果向量中,并await完成,如下所示:

//# tokio = { version = "0.2.4", features = ["full"] }
//# futures = "0.3.1"
use tokio::time::delay_for;
use futures::stream::StreamExt;
use futures::stream::futures_unordered::FuturesUnordered;
use std::error::Error;
use std::time::{Duration, Instant};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let start = Instant::now();
    let feeds = (0..10).collect::<Vec<_>>();
    let res = read_feeds(feeds).await;
    dbg!(res);
    dbg!(start.elapsed());

    Ok(())
}

async fn read_feeds(feeds: Vec<u32>) -> Vec<u32> {
    feeds.iter()
        .map(read_feed)
        .collect::<FuturesUnordered<_>>()
        .collect::<Vec<_>>()
        .await
}

async fn read_feed(feed: &u32) -> u32 {
    delay_for(Duration::from_millis(500)).await;

    feed * 2
}

delay_for用于模拟潜在的昂贵操作。这也有助于证明这些读取确实是并发发生的,而没有任何与线程相关的显式逻辑。

这里有一个细微差别。与同步同步不同,读取rss feed的结果不再是feeds本身的顺序,无论哪个返回值都位于最前面。您需要以某种方式处理。