宣布 tokio-uring:为 Tokio 提供 io-uring 支持
2021年7月19日
今天,我们发布了 “tokio-uring” crate 的第一个版本,为 Linux 上的 io-uring 系统 API 提供支持。此版本提供异步文件操作,我们将在后续版本中添加对更多操作的支持。
要使用 tokio-uring
,首先,添加对 crate 的依赖
tokio-uring = "0.1.0"
然后,启动一个 tokio-uring
运行时并从文件中读取
use tokio_uring::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
tokio_uring::start(async {
// Open a file
let file = File::open("hello.txt").await?;
let buf = vec![0; 4096];
// Read some data, the buffer is passed by ownership and
// submitted to the kernel. When the operation completes,
// we get the buffer back.
let (res, buf) = file.read_at(buf, 0).await;
let n = res?;
// Display the contents
println!("{:?}", &buf[..n]);
Ok(())
})
}
tokio-uring
运行时在底层使用 Tokio 运行时,因此它与 Tokio 类型和库(例如 hyper 和 tonic)兼容。这是与上面相同的示例,但是我们不是写入 STDOUT,而是写入 Tokio TCP 套接字。
use tokio::io::AsyncWriteExt;
use tokio::net::TcpListener;
use tokio_uring::fs::File;
fn main() {
tokio_uring::start(async {
// Start a TCP listener
let listener = TcpListener::bind("0.0.0.0:8080").await.unwrap();
// Accept new sockets
loop {
let (mut socket, _) = listener.accept().await.unwrap();
// Spawn a task to send the file back to the socket
tokio_uring::spawn(async move {
// Open the file without blocking
let file = File::open("hello.txt").await.unwrap();
let mut buf = vec![0; 16 * 1_024];
// Track the current position in the file;
let mut pos = 0;
loop {
// Read a chunk
let (res, b) = file.read_at(buf, pos).await;
let n = res.unwrap();
if n == 0 {
break;
}
socket.write_all(&b[..n]).await.unwrap();
pos += n as u64;
buf = b;
}
});
}
});
}
所有 tokio-uring 操作都是真正的异步,这与 tokio::fs
提供的 API 不同,后者在线程池上运行。从线程池使用同步文件系统操作会增加显著的开销。使用 io-uring
,我们可以从同一个线程异步执行网络和文件系统操作。但是,io-uring 的功能远不止于此。
Tokio 当前的 Linux 实现使用非阻塞系统调用和 epoll 进行事件通知。使用 epoll,一个经过调优的 TCP 代理将在用户空间之外花费 70% 到 80% 的 CPU 周期,包括花费在执行系统调用和在内核与用户空间之间复制数据的周期。Io-uring 通过消除大多数系统调用来减少开销,并且对于某些操作,提前映射用于字节缓冲区的内存区域。早期比较 io-uring 和 epoll 的基准测试很有希望;用 C 实现的 TCP 回显客户端和服务器显示出高达 60% 的改进。
最初的 tokio-uring 版本提供了一组适度的 API,但我们计划在未来的版本中添加对 io-uring 所有功能的支持。请参阅 设计文档 以了解我们的发展方向。
因此,请尝试一下这个 crate,并随时 提问 或 报告问题。
此外,我们要感谢所有一路以来提供帮助的人,特别是 Glauber Costa(Glommio 作者),他耐心地回答了我的许多问题,withoutboats,感谢他的初步探索 (Ringbahn) 并花时间与我讨论设计问题,以及 quininer,感谢他在纯 Rust io-uring bindings 方面所做的出色工作。