当tokio运行时关闭时,使用tokio::spawn创建的任务会在Rust中被丢弃吗?

3
我正在测试使用tokio::spawn创建的任务在主线程终止时的行为。根据tokio文档,当运行时关闭时,所有任务都会被放弃。

不能保证启动的任务将执行完成。当运行时关闭时,所有未完成的任务都将被放弃,而不管该任务的生命周期如何。

然而,当按照以下方式运行测试时,即使运行时终止,任务似乎也没有被终止。

Cargo.toml

[package]
name = "tokio_test"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1", features = ["rt", "test-util", "macros", "rt-multi-thread"]}

main.rs

use std::{thread, time};
#[tokio::main]
async fn main() {
    println!("tokio test - main thread...");
    tokio::spawn(async move {
        let mut i = 0;
        loop {
            println!(
                "tokio test - tokio spawn(worker) thread... sleep(1): {}/10",
                i
            );
            thread::sleep(time::Duration::from_millis(1000));
            i += 1;
         
            if i > 3 {
                break;
            }
        }
      
    });
    thread::sleep(time::Duration::from_millis(1000));
    println!("tokio test - main thread... closed ");
}

输出

tokio test - main thread...
tokio test - tokio spawn(worker) thread... sleep(1): 0/10
tokio test - main thread... closed 
tokio test - tokio spawn(worker) thread... sleep(1): 1/10
tokio test - tokio spawn(worker) thread... sleep(1): 2/10
tokio test - tokio spawn(worker) thread... sleep(1): 3/10

问题

问题1:如果我想在运行时终止时自动终止任务,我是否必须通过任务的JoinHandle直接终止它们?

问题2:如果我在tokio::spawn内部调用tokio::spawn,嵌套任务将不起作用。我不能像这样嵌套tokio::spawn吗?(它显示与输出相同的结果)

tokio::spawn(async move {
    let mut i = 0;
    loop {
        println!(
            "tokio test - tokio spawn(worker) thread... sleep(1): {}/10",
            i
        );
        thread::sleep(time::Duration::from_millis(1000));
        i += 1;
        
        /* nested spawn */
        tokio::spawn(async move {
            println!("worker thread in worker, sleep(1): 10");
            thread::sleep(time::Duration::from_millis(1000));
        });

        if i > 3 {
            break;
        }
    }
});
2个回答

7
这是因为您正在使用std::thread::sleep()。Tokio无法控制阻塞函数,并且它无法在sleep()执行时停止任务。它只能在await点上停止任务。
如果您用tokio::time::sleep().await替换std::thread::sleep(),则该任务会在main()完成后停止。这是一个证明任务确实已被放弃的示例

2
游乐场代码片段应该在主任务中使用 tokio::task::sleep.await,以便内部任务有机会运行。现在它只在创建时运行一次,而不是在睡眠期间运行。 - Michael

-1
也许当 main() 函数关闭时,由 tokio 运行时管理的异步任务队列也会关闭。因此,如果 main() 函数关闭了,新的(spawn)任务将不会被创建。

你是在说第二个问题吗?这只是阻塞运行时的一种情况,即使主函数没有完成,它们也不会运行,直到生成任务完成。 - Chayim Friedman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接