gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 11:46:46 25 4
gpt4 key购买 nike

我正在尝试使用 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/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com