CPU intensive Tokio tasks end up on the same thread

Hi!

I'm running a CPU intensive function over multiple tokio tasks while sending stats via a mpsc into another task to print out stats. Initially all the CPU threads are maxed out as expected.

The problem I saw was the total speed drop over time (and CPU usage drop), and suspected that all the tasks ended up running on one thread. After investigating that seems to be the case. Figured it out by adding an occasional print of thread::current().id() and after 15 or so minutes they all end up being the same thread!

How can I keep them on different threads? Isn't this a strange thing to happen?

Small note: Removing the yield_now() doesn't make a difference.

tokio = { version = "1.4.0", features = ["full", "rt-multi-thread"] }

Thanks for any help :slight_smile:

You should probably be using tokio::task::spawn_blocking() here. The tokio::spawn() function expects you to spawn a "normal" IO bound future, whereas spawn_blocking() will run the task on a background thread.

Thanks for the response! IIUC, spawn_blocking is for when you don't run async. I still want to send messages through a channel.

Besides, I can just use threads directly or something like rayon. I'm just curious why an outcome like this is happening though, and if it's possible to fix? It starts perfectly fine, then moves all those tasks to a single thread for some reason!

I have written a blog post that explains how you should handle CPU intensive code in async: Async: What is blocking?

Tokio's scheduler is optimized for tasks that spend most of their time being idle, and it may make incorrect decisions if they are very CPU-intensive.

Note: You can still use your channel in non-async code through blocking_recv or blocking_send. However, be aware that listening on channels in the rayon thread pool is a bad idea for the same reason as why the blog post earlier recommends dedicated threads for things that run forever.

3 Likes

Note that using the std yield_now like that doesn't make much sense. You need to use the one in Tokio if you want to actually yield to the executor.

Amazing, thank you alice.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.