Futurelock: A subtle risk in async Rust
7 months ago
- #deadlock
- #rust
- #asynchronous-programming
- Futurelock(未来锁)是异步Rust中的一种死锁类型,当一个future拥有的资源被另一个future请求,但负责这两个future的任务却不再轮询第一个future时发生。
- 该问题最初在oxidecomputer/omicron#9259中被发现,可能导致难以调试的隐蔽性程序挂起。
- 常见场景涉及在`tokio::select!`中使用`&mut future`并在某个分支中await,如果这些future共享如Mutex之类的资源就会引发死锁。
- 当从流中提取数据后紧接着await另一个future时,`FuturesOrdered`/`FuturesUnordered`也可能触发futurelock。
- 调试futurelock极具挑战性,其表现为任务挂起,阻塞在未被轮询的future上。
- 缓解策略包括:将future分散到独立任务中执行、避免在`tokio::select!`中使用`&mut future`、不在从流提取数据的循环体内await其他future。
- 使用带`try_send()`的有界通道替代`send().await`可防止通道成为futurelock的组成部分。
- futurelock破坏了Rust关于正确性可局部推理的设计目标,因为问题源于看似独立的结构之间的交互。
- 潜在解决方案包括编写Clippy lint来警告风险模式,例如在`tokio::select!`中使用`&mut future`或在`select!`分支中await。