Rust:tokio可以被理解为类似于Javascripts事件循环,还是可以像它一样使用?
我不确定tokio是否类似于Javascript中的事件循环,也是一个非阻塞运行时,或者它是否可以以类似的方式工作。在我看来,Rust:tokio可以被理解为类似于Javascripts事件循环,还是可以像它一样使用?,rust,async-await,rust-tokio,Rust,Async Await,Rust Tokio,我不确定tokio是否类似于Javascript中的事件循环,也是一个非阻塞运行时,或者它是否可以以类似的方式工作。在我看来,tokio是Rust未来的运行时。因此,它必须实现某种用户线程或任务,这可以通过事件循环(至少部分)来实现,以调度新任务 让我们看一下下面的Javascript代码: console.log('hello1'); setTimeout(() => console.log('hello2'), 0); console.log('hello3'); setTimeout
tokio
是Rust未来的运行时。因此,它必须实现某种用户线程或任务,这可以通过事件循环(至少部分)来实现,以调度新任务
让我们看一下下面的Javascript代码:
console.log('hello1');
setTimeout(() => console.log('hello2'), 0);
console.log('hello3');
setTimeout(() => console.log('hello4'), 0);
console.log('hello5');
输出将是
hello1
hello3
hello5
hello2
hello4
我在东京怎么做?东京总的来说是这样工作的吗?我尝试了以下代码
async fn set_timeout(f: impl Fn(), ms: u64) {
tokio::time::sleep(tokio::time::Duration::from_millis(ms)).await;
f()
}
#[tokio::main]
async fn main() {
println!("hello1");
tokio::spawn(async {set_timeout(|| println!("hello2"), 0)}).await;
println!("hello3");
tokio::spawn(async {set_timeout(|| println!("hello4"), 0)}).await;
println!("hello5");
}
输出刚刚好
hello1
hello3
hello5
如果我把代码改成
println!("hello1");
tokio::spawn(async {set_timeout(|| println!("hello2"), 0)}.await).await;
println!("hello3");
tokio::spawn(async {set_timeout(|| println!("hello4"), 0)}.await).await;
println!("hello5");
输出是
hello1
hello2
hello3
hello4
hello5
但是我没有理解整个async/await/future特性的要点,因为我的“async”set\u timeout-tasks实际上阻止了其他println语句。与JavaScript不同,Rust在等待未来之前不会启动异步函数的执行。这意味着
set_timeout(|println!(“hello2”),0)
只会创造一个新的未来。它根本不执行它。当你等待它时,它才被执行.wait
基本上会阻止当前线程,直到将来完成,这不是“真正的异步应用程序”。要使代码像JavaScript一样并发,可以使用宏:-
使用tokio::join;
使用东京::时间::*;
异步fn设置\u超时(f:impl fn(),ms:u64){
睡眠(持续时间:从μm(ms))。等待;
f()
}
#[tokio::main]
异步fn main(){
println!(“你好”);
让fut|u 1=tokio::spawn(设置|u超时(| | println!(“hello2”),0);
println!(“hello3”);
让fut|u 2=tokio::spawn(设置|u超时(| | println!(“hello4”),0);
println!(“hello5”);
加入!(fut_1,fut_2);
}
如果您想体验一下Promise.all
,可以使用
更多信息:-
- 简言之:是的,Tokio的工作方式与JavaScript事件循环非常相似。但是,您的第一个代码片段有三个问题
首先,它从
main()。与您的JavaScript代码不同,您的JavaScript代码可能在浏览器中运行,甚至在您在控制台中键入的代码完成运行后也会运行超时,而Rust代码位于一个短暂的可执行文件中,在main()
之后终止。如果可执行文件从main()
第二个问题是,调用set\u timeout()
async函数的匿名异步块对其返回值没有任何作用。Rust中的异步函数和JavaScript中的异步函数之间的一个重要区别是,在Rust中,您不能只调用异步函数就可以使用它。在JavaScript中,异步函数返回一个承诺,如果不等待该承诺,事件循环仍将在后台执行异步函数的代码。在Rust中,异步函数返回未来,但它与任何事件循环都没有关联,它只是为某人运行它做好准备。然后,您需要使用.wait
(与JavaScript中的含义相同)等待它,或者显式地将它传递给tokio::spawn()
,以便在后台执行(与调用相同,但不等待JavaScript中的函数)。异步块两者都没有,因此调用set\u timeout()
是不可行的
最后,代码立即等待由spawn()
创建的任务,这首先违背了调用spawn()
的目的-tokio::spawn(foo())。wait
在功能上等同于foo()。wait
用于任何foo()
第一个问题可以通过在main
末尾添加一个小睡眠来解决。(这不是正确的修复,但将用于演示发生了什么。)第二个问题可以通过删除异步块并将set\u timeout()
的返回值传递给tokio::spawn()
来解决。第三个问题通过删除任务中不必要的.wait
来解决
#[tokio::main]
async fn main() {
println!("hello1");
tokio::spawn(set_timeout(|| println!("hello2"), 0));
println!("hello3");
tokio::spawn(set_timeout(|| println!("hello4"), 0));
println!("hello5");
tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
}
此代码将打印“预期的”1、3、5、4、2(尽管在这样的程序中不保证顺序)。真正的代码不会以睡眠结束;相反,它将等待它创建的任务,如Shivam的回答所示。您必须等待main
末尾的所有内容。Tokio不会为你做的-当main
退出时,事件循环立即关闭。我在本地和操场上尝试了这个代码。同样的结果。我如何在tokio中实现Javascripts事件循环中的相同行为?Tokio就是这样工作的吗?如果你想要一个更简单的API,可以使用join\u all
。谢谢,这解释了很多!