Ser*_*rrr 5 rust rust-tokio rust-async-std
我有一些异步函数
async fn get_player(name: String, i: Instant) -> Option<Player> {
// some code here that returns a player structs
}
Run Code Online (Sandbox Code Playgroud)
在我的主函数中,我想在循环中同时运行上述函数,该函数大约需要 1 秒才能完成,并且我需要运行它至少 50 次,因此我想让它同时运行该函数 50 次。在我的主函数中,我有一个lazy_static自定义Client结构,该结构不应创建多次。
主功能
#[tokio::main]
async fn main() {
client.init().await;
println!("start");
for i in 0..10 {
println!("{}", i);
let now = Instant::now();
tokio::spawn(async move {
client.get_player("jay".to_string(), now).await;
});
}
loop {}
}
Run Code Online (Sandbox Code Playgroud)
我传递即时的原因是因为在我的 get_player 函数中我有一个 println!() 只打印执行时间。
上面的 main 方法每个函数调用大约需要 500ms,但是下面的代码只需要 100ms。
#[tokio::main]
async fn maain(){
client.init().await;
for i in 0..10 {
let now = Instant::now();
client.get_player("jay".to_string(), now).await.expect("panic");
}
}
Run Code Online (Sandbox Code Playgroud)
但这个函数仍然是同步代码,我如何在没有时间成本的情况下实际并发运行异步函数?
CompleteableFuture.thenAccept(x -> x.SayHello(););
Run Code Online (Sandbox Code Playgroud)
或者在 Js 中它类似于.then异步函数之后。
Rust中有类似的实现吗?
我假设您的get_player函数需要一秒钟,因为它等待网络交互,而不是因为某些计算需要那么长时间。如果它是受计算限制的,那么异步是错误的方法,您应该改用并行。
此外,我假设 的 函数签名get_player实际上是async fn get_player(&self, name: String, i: Instant) -> Option<Player>相反,因为否则您的main代码示例都没有任何意义。尽管我很困惑为什么会是&self而不是&mut self。
有了这些假设,我尝试重现您的最小可重现示例:
use std::time::{Duration, Instant};
#[derive(Debug)]
struct Player {
name: String,
}
struct Client {}
impl Client {
async fn init(&self) {}
async fn get_player(&self, name: String, _now: Instant) -> Option<Player> {
// Dummy code that simulates a delay of 1 second
tokio::time::sleep(Duration::from_millis(1000)).await;
Some(Player { name })
}
}
static client: Client = Client {};
#[tokio::main]
async fn main() {
let begin = Instant::now();
client.init().await;
for i in 0..10 {
let now = Instant::now();
let player = client
.get_player(format!("Player #{}", i), now)
.await
.expect("panic");
println!(
"[{} ms] Retreived player: {:?}",
begin.elapsed().as_millis(),
player.name
);
}
}
Run Code Online (Sandbox Code Playgroud)
use std::time::{Duration, Instant};
#[derive(Debug)]
struct Player {
name: String,
}
struct Client {}
impl Client {
async fn init(&self) {}
async fn get_player(&self, name: String, _now: Instant) -> Option<Player> {
// Dummy code that simulates a delay of 1 second
tokio::time::sleep(Duration::from_millis(1000)).await;
Some(Player { name })
}
}
static client: Client = Client {};
#[tokio::main]
async fn main() {
let begin = Instant::now();
client.init().await;
for i in 0..10 {
let now = Instant::now();
let player = client
.get_player(format!("Player #{}", i), now)
.await
.expect("panic");
println!(
"[{} ms] Retreived player: {:?}",
begin.elapsed().as_millis(),
player.name
);
}
}
Run Code Online (Sandbox Code Playgroud)
这是基于你的最后一个main例子。正如你所看到的,检索所有玩家需要 10 秒,因为他们都是按顺序运行的。
现在让我们异步运行它们。这里的问题是同时将它们全部加入。遗憾的是,Tokio 并没有提供一种简单的方法。你可以tokio::spawn把它们全部收集起来JoinHandle,然后一一加入。然而,板条箱futures提供的正是您想要的:
use std::time::{Duration, Instant};
#[derive(Debug)]
struct Player {
name: String,
}
struct Client {}
impl Client {
async fn init(&self) {}
async fn get_player(&self, name: String, _now: Instant) -> Option<Player> {
// Dummy code her that simulates a delay of 1 second
tokio::time::sleep(Duration::from_millis(1000)).await;
Some(Player { name })
}
}
static client: Client = Client {};
#[tokio::main]
async fn main() {
let begin = Instant::now();
client.init().await;
let get_player_futures = (0..10).into_iter().map(|i| async move {
let now = Instant::now();
let player = client
.get_player(format!("Player #{}", i), now)
.await
.expect("panic");
println!(
"[{} ms] Retreived player: {:?}",
begin.elapsed().as_millis(),
player.name
);
});
futures::future::join_all(get_player_futures).await;
}
Run Code Online (Sandbox Code Playgroud)
[1002 ms] Retreived player: "Player #0"
[2004 ms] Retreived player: "Player #1"
[3005 ms] Retreived player: "Player #2"
[4008 ms] Retreived player: "Player #3"
[5010 ms] Retreived player: "Player #4"
[6011 ms] Retreived player: "Player #5"
[7013 ms] Retreived player: "Player #6"
[8014 ms] Retreived player: "Player #7"
[9016 ms] Retreived player: "Player #8"
[10018 ms] Retreived player: "Player #9"
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,整个程序只花了一秒钟,而且所有的数据都被同时检索到。
get_player_futures这是一个遍历所有需要等待才能检索玩家的 future 的迭代器。futures::future::join_all然后同时等待他们所有人。您甚至可以使用join_all的返回值来检索 future 的值,但我们在这里不使用它。
我希望这能有所帮助;由于您的问题的某些部分不连贯,因此很难创建答案。
| 归档时间: |
|
| 查看次数: |
6688 次 |
| 最近记录: |