前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >tokio之如何观测Rust异步任务的调度

tokio之如何观测Rust异步任务的调度

作者头像
newbmiao
发布2024-02-26 09:45:40
1410
发布2024-02-26 09:45:40
举报
文章被收录于专栏:学点Rust学点Rust

通过之前的《Rust 异步编程之 Future 初探》我们知道Rust的异步是以task的调度来构建的。task作为抽象在语言层面的调度单元。

那如果想要观测其的调度执行有没有办法呢?

有的!异步runtimetokio就有个tokio-console可以实现对异步调度的观测和分析,其对了解调度的机制和性能分析都很有帮助。

环境设置

其调度的观测是需要依赖程序段添加 console-subscriber 来上报runtime的调度信息,然后由命令行程序tokio-console进行数据的统计展示。

这个功能还属于 unstable,需要引入时做一些设置。

具体来说,需要在引入tokio时启用tracing, 如

代码语言:javascript
复制
[dependencies]
console-subscriber = "0.2.0"
tokio = { version = "1.35.1", features = ["full", "tracing"] }

异步代码main中也需要初始化console_subscriber

代码语言:javascript
复制
#[tokio::main]
async fn main() {
    console_subscriber::init();
    // ...
}

代码运行时需要加上编译参数:RUSTFLAGS="--cfg tokio_unstable" cargo run

也可以在项目根目录用.cargo/config.toml全局配置, 如

代码语言:javascript
复制
[build]
rustflags = ["--cfg", "tokio_unstable"]

这样同时运行tokio-console就能观测异步任务的调度了。

cargo install tokio-console可以安装)

代码改造

以之前《Rust 并发控制之 Semaphore-两线程交替打印》代码来观测为例

修改部分详见代码注释:

代码语言:javascript
复制
use std::{sync::Arc, time::Duration};
use tokio::{sync::Semaphore, task, time::sleep};

#[tokio::main]
async fn main() {
    // 注意. 初始化tracing收集
    console_subscriber::init();
    // 线程1的令牌桶1初始一个令牌,可以先打印1
    let semaphore = Arc::new(Semaphore::new(1));
    let cnt = 3;
    let semaphore2 = semaphore.clone();

    // 线程2的令牌桶2初始没有令牌,直到1打印后增加令牌
    let semaphore_wait = Arc::new(Semaphore::new(0));
    let semaphore_wait2 = semaphore_wait.clone();

    // 注意. 使用task::Builder来增加task名字,否则等同tokio::spawn
    let t1 = task::Builder::default()
        .name("t1")
        .spawn(async move {
            for i in 0..cnt {
                let permit = semaphore.acquire().await.unwrap();
                print!("1 ");
                 // 注意. 增加等待时间,便于观测
                sleep(Duration::from_secs(i)).await;
                // 消耗令牌,不放回令牌桶1
                permit.forget();
                // 令牌桶2增加令牌,可以打印2
                semaphore_wait2.add_permits(1);
            }
        })
        .unwrap();

    let t2 = task::Builder::default()
        .name("t2")
        .spawn(async move {
            for i in 0..cnt {
                let permit = semaphore_wait.acquire().await.unwrap();
                print!("2 ");
                // 注意. 增加等待时间,便于观测
                sleep(Duration::from_secs(i)).await;
                // 消耗令牌,不放回令牌桶2
                permit.forget();
                // 令牌桶1增加令牌,可以打印1
                semaphore2.add_permits(1);
            }
        })
        .unwrap();

    tokio::try_join!(t1, t2).unwrap();
}

观测效果

得到的观测结果如下,可以切换为task视图(按键t)和resource视图(按键r):

task

对于task能看到调度时间(Total, Busy, Sched, Idle),次数(Polls),状态(state)等。

想详细了解时间可以看看这篇博客:task-scheduled-time-in-console[1]

task

左右按键可以选择列,上下按键可以选择行,回车会展开对应行详情, 比如task-t2

里边能看到相应 waker 的一些信息,也会有更细粒度的时间分布图

比较容易发现耗时不正常的task

task-detail

resource

对于resource, 能看到执行了哪些类型的异步操作

resource

详情中是对这个操作不同时间调用的详细展开。

比如t2semaphore_wait.acquire的三次调用

resource-details

本文代码详见tokio-play[2]

想查看更多异步观测的例子建议查看下官方的例子[3]

参考资料

[1]

task-scheduled-time-in-console: https://hegdenu.net/posts/task-scheduled-time-in-console/

[2]

tokio-play: https://github.com/NewbMiao/rust-koan/tree/master/tokio-play

[3]

官方的例子: https://github.com/tokio-rs/console/tree/main/console-subscriber/examples

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-01-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 菜鸟Miao 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 环境设置
  • 代码改造
  • 观测效果
    • task
      • resource
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档