Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why does Tokio single threaded flavor not provide any concurrency?

When I am running the below code with flavor = "current_thread", I am seeing output only from first task and not the other. My understanding was that even in a single threaded execution, async code can be run concurrently. What am I missing?

use std::{
    thread,
    time::{Duration, SystemTime},
};

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let handle_1 = tokio::spawn(async move {
        loop {
            println!("{:?} Hello from 1", SystemTime::now());
            thread::sleep(Duration::from_millis(2000))
        }
    });
    let handle_2 = tokio::spawn(async move {
        loop {
            println!("{:?} Hello from 2", SystemTime::now());
            thread::sleep(Duration::from_millis(5000))
        }
    });
    handle_1.await.unwrap();
    handle_2.await.unwrap();
}

(Playground)

Output

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

SystemTime { tv_sec: 1719896401, tv_nsec: 253252588 } Hello from 1
SystemTime { tv_sec: 1719896403, tv_nsec: 253411156 } Hello from 1
SystemTime { tv_sec: 1719896405, tv_nsec: 253504834 } Hello from 1
SystemTime { tv_sec: 1719896407, tv_nsec: 253627641 } Hello from 1
SystemTime { tv_sec: 1719896409, tv_nsec: 253785910 } Hello from 1
SystemTime { tv_sec: 1719896411, tv_nsec: 254074102 } Hello from 1
SystemTime { tv_sec: 1719896413, tv_nsec: 254410243 } Hello from 1
SystemTime { tv_sec: 1719896415, tv_nsec: 254574553 } Hello from 1
SystemTime { tv_sec: 1719896417, tv_nsec: 254955748 } Hello from 1
SystemTime { tv_sec: 1719896419, tv_nsec: 258449707 } Hello from 1
SystemTime { tv_sec: 1719896421, tv_nsec: 258703255 } Hello from 1
SystemTime { tv_sec: 1719896423, tv_nsec: 258839315 } Hello from 1
SystemTime { tv_sec: 1719896425, tv_nsec: 259088384 } Hello from 1
SystemTime { tv_sec: 1719896427, tv_nsec: 259232553 } Hello from 1
SystemTime { tv_sec: 1719896429, tv_nsec: 260017836 } Hello from 1

>Solution :

Only one task ever runs, because you are blocking entire thread. Use tokio::time::sleep to communicate to your runtime that task should yield whilst sleeping.

use std::{
    time::{Duration, SystemTime},
};

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let handle_1 = tokio::spawn(async move {
        loop {
            println!("{:?} Hello from 1", SystemTime::now());
            tokio::time::sleep(Duration::from_millis(2000)).await;
        }
    });
    let handle_2 = tokio::spawn(async move {
        loop {
            println!("{:?} Hello from 2", SystemTime::now());
            tokio::time::sleep(Duration::from_millis(5000)).await;
        }
    });
    handle_1.await.unwrap();
    handle_2.await.unwrap();
}

In general you shouldn’t use blocking code inside async. You can cause all sorts of deadlocks that way. If you need to use blocking code in tokio, use tokio::task::spawn_blocking, which will run provided closure on the another threadpool, dedicated to blocking tasks.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading