phi*_*611 7 rust async-await rust-tokio
我不确定它是否tokio类似于 Javascript 中的事件循环,也是一个非阻塞运行时,或者它是否可以用于以类似的方式工作。以我的理解,tokio是 Rust 中 future 的运行时。因此,它必须实现某种用户态线程或任务,这可以通过事件循环(至少部分)来调度新任务来实现。
我们来看下面的 Javascript 代码:
console.log('hello1');
setTimeout(() => console.log('hello2'), 0);
console.log('hello3');
setTimeout(() => console.log('hello4'), 0);
console.log('hello5');
Run Code Online (Sandbox Code Playgroud)
输出将是
hello1
hello3
hello5
hello2
hello4
Run Code Online (Sandbox Code Playgroud)
我怎样才能在东京做到这一点?tokio 总体上是这样工作的吗?我尝试了以下代码
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");
}
Run Code Online (Sandbox Code Playgroud)
输出只是
hello1
hello3
hello5
Run Code Online (Sandbox Code Playgroud)
如果我将代码更改为
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");
Run Code Online (Sandbox Code Playgroud)
输出是
hello1
hello2
hello3
hello4
hello5
Run Code Online (Sandbox Code Playgroud)
但后来我不明白整个 async/await/future 功能的意义,因为我的“async”set_timeout-tasks 实际上阻塞了其他 println 语句。
In short: yes, Tokio is meant to work much like the JavaScript event loop. However, there are three problems with your first snippet.
First, it returns from main() before waiting for things to play out. Unlike your JavaScript code, which presumably runs in the browser, and runs the timeouts even after the code you typed in the console has finished running, the Rust code is in a short-lived executable which terminates after main(). Whatever things were scheduled to happen later won't occur if the executable stops running because it returned from main().
The second issue is that the anonymous async block that calls the set_timeout() async function doesn't do anything with its return value. An important difference between async functions in Rust and JavaScript is that in Rust you can't just call an async function and be done with it. In JavaScript an async function returns a promise, and if you don't await that promise, the event loop will still execute the code of the async function in the background. In Rust, an async function returns a future, but it is not associated with any event loop, it is just prepared for someone to run it. You then need to either await it with .await (with the same meaning as in JavaScript) or explicitly pass it to tokio::spawn() to execute in the background (with the same meaning as calling but not awaiting the function in JavaScript). Your async block does neither, so the invocation of set_timeout() is a no-op.
Finally, the code immediately awaits the task created by spawn(), which defeats the purpose of calling spawn() in the first place - tokio::spawn(foo()).await is functionally equivalent to foo().await for any foo().
The first issue can be resolved by adding a tiny sleep at the end of main. (This is not the proper fix, but will serve to demonstrate what happens.) The second issue can be fixed by removing the async block and just passing the return value of set_timeout() to tokio::spawn(). The third issue is resolved by removing the unnecessary .await of the task.
#[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;
}
Run Code Online (Sandbox Code Playgroud)
此代码将打印“预期”1、3、5、4、2(尽管在此类程序中不能保证顺序)。sleep真正的代码不会以;结尾 相反,它会等待它创建的任务,如 Shivam 的回答所示。
| 归档时间: |
|
| 查看次数: |
2788 次 |
| 最近记录: |