5个版本
0.2.1 | 2024年4月1日 |
---|---|
0.2.0 | 2024年3月28日 |
0.1.2 | 2023年10月22日 |
0.1.1 | 2023年3月1日 |
0.1.0 | 2023年2月28日 |
#248 in 调试
9,218 每月下载量
在 2 crates 中使用
45KB
779 行
await-tree
异步Rust中的Future
可以任意组合或嵌套以实现各种控制流。假设每个Future
的执行表示为一个节点,那么异步任务的异步执行可以组织成一个逻辑树,该树在Future
的轮询、完成和取消过程中不断转换。
await-tree
允许开发者以运行时String
自定义跨度,每个Future
的跨度都由instrument_await
标注。以下是一个基本示例,更多复杂控制流的示例可以在示例目录中找到。
async fn bar(i: i32) {
// `&'static str` span
baz(i).instrument_await("baz in bar").await
}
async fn baz(i: i32) {
// runtime `String` span is also supported
pending()
.instrument_await(format!("pending in baz {i}"))
.await
}
async fn foo() {
// spans of joined futures will be siblings in the tree
join(
bar(3).instrument_await("bar"),
baz(2).instrument_await("baz"),
)
.await;
}
let root = register("foo");
tokio::spawn(root.instrument(foo()));
sleep(Duration::from_secs(1)).await;
let tree = get_tree("foo");
// foo [1.006s]
// bar [1.006s]
// baz in bar [1.006s]
// pending in baz 3 [1.006s]
// baz [1.006s]
// pending in baz 2 [1.006s]
println!("{tree}");
与async-backtrace
相比
tokio-rs/async-backtrace
是一个类似的crate,也提供了转储异步任务执行树的功能。以下是await-tree
和async-backtrace
之间的一些区别
await-tree
的优点:
-
await-tree
支持使用运行时String
自定义跨度,而async-backtrace
仅支持函数名和行号。当我们需要使用一些动态信息,如共享资源的标识符(例如,一个锁),来注释跨度时,这很有用,以便了解不同任务之间如何发生竞争。
-
await-tree
支持几乎所有类型的异步控制流,具有任意的Future
拓扑,而async-backtrace
无法处理其中的一些。例如,通常使用
&mut impl Future
作为select
的一个分支,以避免取消不安全引起的问题。为了在select
完成后进一步解决这个Future
,我们可以将其移动到另一个位置并在那里await
它。async-backtrace
由于其父级的变化而无法再次跟踪此Future
。有关更多详细信息,请参阅examples/detach.rs
。 -
await-tree
使用基于竞技场的数据结构维护树结构,没有额外的unsafe
代码。相比之下,async-backtrace
手动构建它,并且上述未处理的拓扑可能存在内存不安全的风险。值得注意的是,
await-tree
已经在分布式流数据库RisingWave的生产部署中长期使用。 -
await-tree
将树结构与Future
本身分开维护,这使得开发人员可以在几乎无争用的情况下随时转储树,无论Future
是处于活动轮询还是已经挂起。相比之下,async-backtrace
必须在转储树之前等待轮询完成,这可能导致长时间的延迟。
async-backtrace
的优点:
async-backtrace
处于Tokio组织之下。
许可协议
await-tree
采用Apache License(版本2.0)进行分发。有关更多信息,请参阅LICENSE。
依赖关系
~4–11MB
~109K SLoC