[Rust] tokio: tokio-console

tokio-console์€ tokio ์ „์šฉ ๋””๋ฒ„๊น… ๋„๊ตฌ ํ™˜๊ฒฝ์ด๋‹ค.
๋ณต์žกํ•œ ๋™์‹œ์„ฑ ํ™˜๊ฒฝ์—์„œ์˜ ๋ฆฌ์†Œ์Šค ์ถ”์ , ๋””๋ฒ„๊น… ๋“ฑ์„ ์šฉ์ดํ•˜๊ฒŒ ํ•ด์ค€๋‹ค.




console CLI ์„ค์น˜

๋จผ์ € cargo install์„ ํ†ตํ•ด ๋„๊ตฌ๋ฅผ ์„ค์น˜ํ•œ๋‹ค.

cargo install --locked tokio-console

๊ทธ๋ฆฌ๊ณ  ์‹คํ–‰ํ•ด๋ณด๋ฉด

tokio-console

๋ณ„ ์˜๋ฏธ์žˆ๋Š”๊ฑด ์•ˆ๋œฐ ๊ฒƒ์ด๋‹ค.
์ด๊ฑด ๊ธฐ๋ณธ์ ์œผ๋กœ client ๋„๊ตฌ๊ณ , grpc๋ฅผ ํ†ตํ•ด ํŠธ๋ ˆ์ด์‹ฑ์„ ์ผœ์ค€ ์•ฑ ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๋ฉฐ ๊ธฐ๋ก์„ ๋ณด์—ฌ์ค€๋‹ค.

์ด์ œ ์•ฑ์„ ๊ตฌ์„ฑํ•ด๋ณด์ž.




์•ฑ ๊ตฌ์„ฑ

tokio ์•ฑ์ด๋‹ˆ๊นŒ tokio๋Š” ๋‹น์—ฐํžˆ ์žˆ์–ด์•ผํ•˜๊ณ , console-subscriber ์ข…์†์„ฑ์ด ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•˜๋‹ค.

tokio์˜ ์‹คํ—˜์  ๊ธฐ๋Šฅ์ธ tracing๋„ ํ•„์š”ํ•˜๋‹ค. ๋„ฃ์–ด์ค€๋‹ค.

์˜ˆ์ œ์ฝ”๋“œ๋‹ค.

use std::{error::Error, thread};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    console_subscriber::init();

    loop {
        tokio::spawn(async {
            std::thread::sleep(std::time::Duration::from_secs(10));
            println!("done");
        });

        thread::sleep(std::time::Duration::from_secs(1));
    }
}

๋ณ„๊ฑด ์—†๋‹ค.
๋ฃจํ”„๋Œ๋ฉด์„œ ๋А๋ฆฟ๋А๋ฆฟํ•˜๊ฒŒ ํƒœ์Šคํฌ๋ฅผ ํ•˜๋‚˜์”ฉ ๋„์šฐ๊ณ , 10์ดˆ๊ฐ€ ์ง€๋‚˜๋ฉด ๋กœ๊ทธ์ฐ๊ณ  ์ฃฝ๋Š”๊ฒŒ ๋‹ค๋‹ค.
๋กœ์ง๊ณผ ๋ณ„๊ฐœ๋กœ console_subscriber::init(); ์ดˆ๊ธฐ ์„ ์–ธ ํ•œ๋ฒˆ๋งŒ ํ•ด์ฃผ๋ฉด tracing ์„œ๋ฒ„๊ฐ€ ๋œฌ๋‹ค. ์ €๊ฒŒ ์ค‘์š”ํ•˜๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹คํ–‰์„ ํ•ด์ค€๋‹ค.

RUSTFLAGS="--cfg tokio_unstable" cargo run

์ €๋ ‡๊ฒŒ ์„œ๋ฒ„๊ฐ€ ๋œจ๊ณ  ๋‚˜์„œ

tokio-console์„ ๋‹ค์‹œ ์ผœ๋ณด๋ฉด

์ด๋ฒˆ์—๋Š” ์—ฐ๊ฒฐ์ด ๋  ๊ฒƒ์ด๋‹ค.
์—ฌ๊ธฐ์„œ ๋ชจ๋“  ํƒœ์Šคํฌ์˜ ํ˜„ํ™ฉ์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
์‹คํ–‰์ค‘์ธ ํƒœ์Šคํฌ๋Š” โ–ถ, ์ผ์‹œ์ •์ง€ ์ƒํƒœ(sleep)๋Š” โธ. ์ •์ง€๋œ ํƒœ์Šคํฌ๋Š” โน ๋กœ ํ‘œ์‹œ๋œ๋‹ค.

๊ฐ๊ฐ์˜ ํƒœ์Šคํฌ๊ฐ€ ๋œฌ ์ค„๋„ ๋œจ๊ณ , ์ด๋Ÿฐ์ €๋Ÿฐ ์ •๋ณด๋“ค์ด ๊ฝค ํ‘œ์‹œ๋œ๋‹ค.


์—”ํ„ฐ์ณ์„œ ํƒœ์Šคํฌ ์ƒ์„ธ๋กœ ๋“ค์–ด๊ฐ€๋ฉด ์กฐ๊ธˆ ๋” ๋งŽ์€ ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.




๋‹ค๋ฅธ ์˜ˆ์ œ: long sleep

์•„๋ž˜๋Š” ๋น„์ •์ƒ์ ์ธ ์ •๋„๋กœ sleep์„ ๊ฑธ๊ณ  ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š” ํƒœ์Šคํฌ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ ๋‹ค.

use std::{error::Error, time::Duration};

use tokio::task::yield_now;

async fn long_sleeps(inc: u64) {
    let millis = inc;
    loop {
        std::thread::sleep(Duration::from_millis(millis));

        yield_now().await;
    }
}

async fn sleep_forever(inc: u64) {
    let millis = inc;
    loop {
        std::thread::sleep(Duration::from_millis(millis));
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    console_subscriber::init();

    let long_sleeps = tokio::task::Builder::new()
        .name("long-sleeps")
        .spawn(long_sleeps(5000))
        .unwrap();

    let sleep_forever = tokio::task::Builder::new()
        .name("sleep-forever")
        .spawn(sleep_forever(5000))
        .unwrap();

    match (long_sleeps.await, sleep_forever.await) {
        (Ok(_), Ok(_)) => println!("Success"),
        (_, _) => println!("Error awaiting tasks."),
    }

    tokio::time::sleep(Duration::from_millis(200)).await;

    Ok(())
}

long_sleeps๋„ ๋ฌดํ•œ์œผ๋กœ ๋Œ๊ธด ํ•˜์ง€๋งŒ, yield๋ฅผ ํ†ตํ•ด ์–‘๋ณด๋ฅผ ํ•˜๋Š” ๋ฐ˜๋ฉด sleep_forever์€ ๋Œ€์ฑ…์—†์ด ๋ฃจํ”„๋ฅผ ๋Œ๋ฉฐ ๋ฆฌ์†Œ์Šค๋ฅผ ์ ์œ ํ•œ๋‹ค.


๊ทธ๋Ÿผ ์ด๋Ÿฐ์‹์œผ๋กœ ๊ฒฝ๊ณ ๊ฐ€ ํ•ญ์ƒ ๋œฌ๋‹ค.
๋ฐ๋“œ๋ฝ์ด ๋ฐœ์ƒํ•ด๋„ ์ด๋Ÿฐ ๋А๋‚Œ์œผ๋กœ ๋œจ๋”๋ผ




๋‹ค๋ฅธ ์˜ˆ์ œ: mutex deadlock

์•„๋ž˜๋Š” Mutex๋ฅผ ํ†ตํ•ด ๋ฐ๋“œ๋ฝ์„ ์œ ๋ฐœ์‹œํ‚ค๋Š” ์˜ˆ์ œ ์ฝ”๋“œ๋‹ค.
ํฌ๊ฒŒ ํŠน๋ณ„ํ•œ ๊ฒƒ์€ ์—†๋‹ค.

use std::sync::{Arc, Mutex};

#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    console_subscriber::init();

    let a = Arc::new(Mutex::new(0));
    let b = Arc::new(Mutex::new(0));

    {
        let a = a.clone();
        let b = b.clone();
        tokio::task::Builder::default()
            .name("A")
            .spawn(async move {
                let mut a_num = a.lock().unwrap();
                *a_num += 1;

                let delay = std::time::Duration::from_millis(1000);
                std::thread::sleep(delay);
                let mut b_num = b.lock().unwrap();
                *b_num += 1;
            })
            .unwrap();
    }

    {
        let a = a.clone();
        let b = b.clone();
        tokio::task::Builder::default()
            .name("B")
            .spawn(async move {
                let mut b_num = b.lock().unwrap();
                *b_num += 1;

                let delay = std::time::Duration::from_millis(1000);
                let mut a_num = a.lock().unwrap();
                *a_num += 1;
            })
            .unwrap();
    }

    Ok(())
}

์„œ๋กœ์„œ๋กœ lock์„ ๊ฑธ๋ฉด์„œ ๋จนํ†ต๋˜๋Š” ์ „ํ˜•์ ์ธ ๋ฐ๋“œ๋ฝ ์ฝ”๋“œ๋‹ค.

์ €๊ฑธ ๊ด€์ธกํ•˜๋ฉด

์ด๋Ÿฐ ๋А๋‚Œ์œผ๋กœ ๋œฌ๋‹ค.