Rust 如何以稳定的方式同步返回异步未来计算的值?

Rust 如何以稳定的方式同步返回异步未来计算的值?,rust,future,hyper,Rust,Future,Hyper,我正在尝试使用hyper获取HTML页面的内容,并希望同步返回未来的输出。我意识到我可以选择一个更好的例子,因为同步HTTP请求已经存在,但我更感兴趣的是理解我们是否可以从异步计算返回值 extern crate futures; extern crate hyper; extern crate hyper_tls; extern crate tokio; use futures::{future, Future, Stream}; use hyper::Client; use hyper::

我正在尝试使用hyper获取HTML页面的内容,并希望同步返回未来的输出。我意识到我可以选择一个更好的例子,因为同步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);
}
我知道我在以后调用
.wait()
之前未能正确启动任务,但我找不到正确的方法,假设这是可能的。

Standard library futures 让我们将其用作我们的:

电话:

东京 使用任何函数(不仅仅是
main
!)上的属性将其从异步函数转换为同步函数:

use tokio; // 0.3.5

#[tokio::main]
async fn main() {
    let v = example().await;
    println!("{}", v);
}
use async_std; // 1.6.5, features = ["attributes"]

#[async_std::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 { {} })
}
这在引擎盖下使用,因此您也可以这样写:

use tokio::runtime::Runtime; // 0.3.5

fn main() {
    let v = Runtime::new().unwrap().block_on(example());
    println!("{}", v);
}
对于测试,您可以使用

异步标准 使用
main
函数上的属性将其从异步函数转换为同步函数:

use tokio; // 0.3.5

#[tokio::main]
async fn main() {
    let v = example().await;
    println!("{}", v);
}
use async_std; // 1.6.5, features = ["attributes"]

#[async_std::main]
async fn main() {
    let v = example().await;
    println!("{}", v);
}
对于测试,您可以使用

期货0.1 让我们将其用作我们的:

然而,这带来了一个相当严重的警告:

此方法不适用于调用事件循环或类似的I/O情况,因为它会阻止事件循环进行(这会阻塞线程)。只有在保证与此未来相关的阻塞工作将由另一个线程完成时,才应调用此方法

东京 如果您使用的是Tokio 0.1,您应该使用Tokio的:

如果您在上查看
block_的实现,它实际上会将未来的结果发送到一个通道,然后在该通道上调用
wait
!这很好,因为Tokio保证在未来运行到完成

另见:


这对我使用tokio很有效:

tokio::runtime::Runtime::new()?.block_on(fooAsyncFunction())?;

在futures 0.1中,对于简单的情况,您只需要调用wait:在我看来,它不是很清楚:它只在未来立即解决时才起作用。当你将来有事情要解决时,你需要一个运行时,同样对于简单的情况也是如此。@Shepmaster,从Rust 1.45开始,有没有标准的方法(不使用其他板条箱)来解决这个问题?@Amani no.另请参见@Shepmaster,谢谢。我认为这是一个路障,希望有一天我们会有它?@Amani如果你认为在你的货物上添加一行。toml是一个“路障”,那么生锈可能不是你喜欢使用的语言。通常可能会有更多的东西被转移到标准库中,但这样做的动力并不强,特别是当有多种方法解决问题时,一种方法对另一种方法没有明显的好处,而且很容易添加依赖项。
fn main() {
    let s = example().wait();
    println!("{:?}", s);
}
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);
}
tokio::runtime::Runtime::new()?.block_on(fooAsyncFunction())?;