我正在尝试使用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()
的调用却出现了以下错误消息,从而引起了恐慌:
Content = Err("Error scraping web page: Error { kind: Execute, cause: None }")
我了解到在将来致电.wait()
之前,我无法正确启动任务,但即使有可能,我也找不到正确的方法。
答案 0 :(得分:5)
让我们将其用作我们的MCVE:
extern crate futures; // 0.1.24
use futures::{future, Future};
fn example() -> impl Future<Item = i32, Error = ()> {
future::ok(42)
}
在期货0.1中,对于简单的情况,您只需致电wait
:
fn main() {
let s = example().wait();
println!("{:?}", s);
}
但是,这带有一个非常严重的警告:
此方法不适用于事件循环或类似的I / O情况,因为它将阻止事件循环进行(这将阻塞线程)。仅在确保与此将来关联的阻塞工作将由另一个线程完成时,才应调用此方法。
如果您使用的是Tokio,则应使用Tokio的Runtime::block_on
:
extern crate tokio; // 0.1.8
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
的实现,它实际上会将未来结果发送到一个通道,然后在该通道上调用wait
!之所以这样,是因为Tokio保证将来会继续发展。
另请参阅:
答案 1 :(得分:0)
这对我使用 tokio 有效:
tokio::runtime::Runtime::new()?.block_on(fooAsyncFunction())?;