rust - 如何在稳定的 Rust 中同步返回在异步 Future 中计算的值?

标签 rust future hyper

我正在尝试使用 hyper 来获取 HTML 页面的内容,并希望同步返回 future 的输出。我意识到我可以选择一个更好的例子,因为同步 HTTP 请求已经存在,但我更感兴趣的是了解我们是否可以从异步计算中返回一个值。

extern crate futures;
extern crate hyper;
extern crate hyper_tls;
extern crate tokio;

use futures::{future, Future, Stream};
use hyper::Client;
use hyper::Uri;
use hyper_tls::HttpsConnector;

use std::str;

fn scrap() -> Result<String, String> {
    let scraped_content = future::lazy(|| {
        let https = HttpsConnector::new(4).unwrap();
        let client = Client::builder().build::<_, hyper::Body>(https);

        client
            .get("https://hyper.rs".parse::<Uri>().unwrap())
            .and_then(|res| {
                res.into_body().concat2().and_then(|body| {
                    let s_body: String = str::from_utf8(&body).unwrap().to_string();
                    futures::future::ok(s_body)
                })
            }).map_err(|err| format!("Error scraping web page: {:?}", &err))
    });

    scraped_content.wait()
}

fn read() {
    let scraped_content = future::lazy(|| {
        let https = HttpsConnector::new(4).unwrap();
        let client = Client::builder().build::<_, hyper::Body>(https);

        client
            .get("https://hyper.rs".parse::<Uri>().unwrap())
            .and_then(|res| {
                res.into_body().concat2().and_then(|body| {
                    let s_body: String = str::from_utf8(&body).unwrap().to_string();
                    println!("Reading body: {}", s_body);
                    Ok(())
                })
            }).map_err(|err| {
                println!("Error reading webpage: {:?}", &err);
            })
    });

    tokio::run(scraped_content);
}

fn main() {
    read();
    let content = scrap();

    println!("Content = {:?}", &content);
}

示例编译并调用 read()成功,但调用 scrap()出现以下错误消息的 panic :

Content = Err("Error scraping web page: Error { kind: Execute, cause: None }")

我了解在调用 .wait() 之前未能正确启动任务在 future ,但我找不到如何正确地做到这一点,假设它甚至是可能的。

最佳答案

标准库 future
让我们用它作为我们的minimal, reproducible example :

async fn example() -> i32 {
    42
}
调用 executor::block_on :
use futures::executor; // 0.3.1

fn main() {
    let v = executor::block_on(example());
    println!("{}", v);
}
东京
使用 tokio::main 任何函数(不仅仅是 main !)的属性,以将其从异步函数转换为同步函数:
use tokio; // 0.3.5

#[tokio::main]
async fn main() {
    let v = example().await;
    println!("{}", v);
}
tokio::main是一个转换这个的宏
#[tokio::main]
async fn main() {}
进入这个:
fn main() {
    tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .build()
        .unwrap()
        .block_on(async { {} })
}
这使用 Runtime::block_on 在引擎盖下,所以你也可以这样写:
use tokio::runtime::Runtime; // 0.3.5

fn main() {
    let v = Runtime::new().unwrap().block_on(example());
    println!("{}", v);
}
对于测试,您可以使用 tokio::test .
异步标准
使用 async_std::main main 上的属性函数将其从异步函数转换为同步函数:
use async_std; // 1.6.5, features = ["attributes"]

#[async_std::main]
async fn main() {
    let v = example().await;
    println!("{}", v);
}
对于测试,您可以使用 async_std::test .
future 0.1
让我们用它作为我们的minimal, reproducible example :
use futures::{future, Future}; // 0.1.27

fn example() -> impl Future<Item = i32, Error = ()> {
    future::ok(42)
}
对于简单的情况,您只需调用wait :
fn main() {
    let s = example().wait();
    println!("{:?}", s);
}
然而,这伴随着一个非常严重的警告:

This method is not appropriate to call on event loops or similar I/O situations because it will prevent the event loop from making progress (this blocks the thread). This method should only be called when it's guaranteed that the blocking work associated with this future will be completed by another thread.


东京
如果你使用的是 Tokio 0.1,你应该使用 Tokio 的 Runtime::block_on :
use tokio; // 0.1.21

fn main() {
    let mut runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime");
    let s = runtime.block_on(example());
    println!("{:?}", s);
}
如果你偷看 block_on 的实现,它实际上将 future 的结果发送到一个 channel ,然后调用 wait在那个 channel !这很好,因为 Tokio 保证将 future 运行到完成。
也可以看看:
  • How can I efficiently extract the first element of a futures::Stream in a blocking manner?
  • 关于rust - 如何在稳定的 Rust 中同步返回在异步 Future 中计算的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66207375/

    相关文章:

    rust-tokio - 如何将超响应正文写入文件?

    ssl - 使用 Let's Encrypt 证书的 Nickel 服务器在使用 ruSTL 访问时出现握手错误

    struct - 如何使用特征的不同实现实例化相同的结构?

    generics - 无法创建多态类型,因为无法将特征制成对象

    vector - 获取存储在 n 维向量中的元素数

    rust - 如何返回 Arc<Vec<u8>> 作为 super 响应?

    rust - 在 Rust 中的 extprim::u128::u128 和原始 u128 之间转换?

    flutter - 什么是 future ,我将如何使用它?

    scala - 使用猫从 future 中提取值(value)

    java - 方法什么时候应该返回 CompletableFuture?