通过之前的《Rust 异步编程之 Future 初探》我们知道Rust
的异步是以task
的调度来构建的。task
作为抽象在语言层面的调度单元。
那如果想要观测其的调度执行有没有办法呢?
有的!异步runtime
库tokio
就有个tokio-console
可以实现对异步调度的观测和分析,其对了解调度的机制和性能分析都很有帮助。
其调度的观测是需要依赖程序段添加 console-subscriber
来上报runtime
的调度信息,然后由命令行程序tokio-console
进行数据的统计展示。
这个功能还属于 unstable,需要引入时做一些设置。
具体来说,需要在引入tokio
时启用tracing
, 如
[dependencies]
console-subscriber = "0.2.0"
tokio = { version = "1.35.1", features = ["full", "tracing"] }
异步代码main
中也需要初始化console_subscriber
#[tokio::main]
async fn main() {
console_subscriber::init();
// ...
}
代码运行时需要加上编译参数:RUSTFLAGS="--cfg tokio_unstable" cargo run
也可以在项目根目录用.cargo/config.toml
全局配置, 如
[build]
rustflags = ["--cfg", "tokio_unstable"]
这样同时运行tokio-console
就能观测异步任务的调度了。
(cargo install tokio-console
可以安装)
以之前《Rust 并发控制之 Semaphore-两线程交替打印》代码来观测为例
修改部分详见代码注释:
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
能看到调度时间(Total, Busy, Sched, Idle
),次数(Polls
),状态(state
)等。
想详细了解时间可以看看这篇博客:task-scheduled-time-in-console[1]
task
左右按键可以选择列,上下按键可以选择行,回车会展开对应行详情, 比如task-t2
里边能看到相应 waker 的一些信息,也会有更细粒度的时间分布图
比较容易发现耗时不正常的task
。
task-detail
对于resource
, 能看到执行了哪些类型的异步操作
resource
详情中是对这个操作不同时间调用的详细展开。
比如t2
中semaphore_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
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有