Why does a task spawned with `task::spawn` not get executed when it's inside of a loop, inside another blocking task?

huangapple go评论89阅读模式
英文:

Why does a task spawned with `task::spawn` not get executed when it's inside of a loop, inside another blocking task?

问题

我正在学习Rust,并遇到了一个无法解释的情况。我有一个阻塞操作(监听网络接口上的数据包),我将其转移到另一个线程中。一切都正常工作,但我还需要对这些数据包进行另一组操作,所以我想在另一个线程/任务中处理它们。

我发现第二个线程/任务从未启动,我无法确定原因。

代码是在Tokio中运行的,所以我的主函数被注解为#[tokio::main(flavor = "multi_thread", worker_threads = 10)]。其中包含以下代码(我试图将问题隔离到最简形式):

task::spawn_blocking(move || {
    println!("Spawned blocking!"); // 正确执行

    loop { // 在这个循环中,我等待一个.next()数据包
        println!("PRE SPAWN"); // 正常执行,如预期所示
        tokio::spawn(async move { 
            // 这个代码块应该以不阻塞等待下一个数据包的方式处理数据包
            println!("Spawned INSIDE blocking!"); // 从未调用
        });
    }
});
英文:

I'm studying Rust and I encountered a scenario which I can't explain. I have a blocking operation (listening on a network interface for packets) which I'm offloading to another thread. Everything works fine then, but I have another set of operations I need to do on those packets, and for this I figured I'd spawn another thread/task and have it handle those.

What I found out is that this second thread/task never gets started, and I can't pin-point why.

The code is running with Tokio, so my main function is annotated with #[tokio::main(flavor = "multi_thread", worker_threads = 10)]. Inside of it comes this (I've tried to isolate the problem to this simplest form):

task::spawn_blocking(move || {
    println!("Spawned blocking!"); // This is executed correctly

    loop { // Inside this loop I wait for a .next() packet
        println!("PRE SPAWN"); // This executes fine, and repeatedly, as expected.
        tokio::spawn(async move { 
            // This block is supposed to process the packet in a way that 
            // doesn't block the waiting for next packets.
            println!("Spawned INSIDE blocking!"); // Never gets called
        });
    }
});

答案1

得分: 2

你看到的行为可能是因为你没有使用await等待相关的future,并且在那里也没有进行任何睡眠或工作,所以最终导致运行时关闭。一旦该过程开始,就不会安排新的任务,因此没有Spawned INSIDE blocking!。但是,生成这些线程的线程不能被突然取消;没有标准的低级API可以使线程停止运行。

文档进一步说明了
> 当你关闭执行器时,它将无限期地等待所有阻塞操作完成。你可以使用shutdown_timeout在一定的超时时间后停止等待。

因此,阻塞任务会继续运行并打印PRE SPAWN

英文:

You see the behaviour you get probably because you don't await the future in question and don't do any other sleeping or work there either so it ends resulting in the runtime shutting down. Once that procedure started no new tasks are being scheduled hence no Spawned INSIDE blocking!. But the thread spawning these
> cannot be cancelled abruptly; there is no standard low level API to cause a thread to stop running.

the docs further state
> When you shut down the executor, it will wait indefinitely for all blocking operations to finish. You can use shutdown_timeout to stop waiting for them after a certain timeout.

So the blocking task keeps on running and printing PRE SPAWN.

huangapple
  • 本文由 发表于 2023年8月9日 01:04:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76861756.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定