IORingSwift 是一个轻量级的 Swift 封装库,用于 io_uring。它的设计目标是性能优先,而非可移植性。它并不打算取代 libdispatch 或 SwiftNIO;事实上,它目前需要前者,并且抽象程度也低于后者。
它最初的设计目的是为了支持嵌入式应用中的 SPI,因为 Linux SPI 用户空间驱动是同步的,但它同样擅长处理套接字。导致其开发的讨论可以在这里找到。
该软件包由两个库组成:
io_uring
请求提供了支持 async/await
的、Swift 并发感知的封装。其目的是最终也支持 Zephyr 中的实时 I/O 子系统,以便与 SwiftIO 及其封装 AsyncSwiftIO 一起使用。
IORing 操作被隔离到 IORingActor
全局 actor 中。
IORing 通常设计为作为单例 (IORing.shared
) 使用,但是由于目前 API 在分配固定缓冲区方面存在一些限制,您可能需要分配单独的实例。目前,所有实例共享相同的 actor 上下文和 io_uring
工作队列,因此分配更多实例没有性能优势。(但这应被视为实现细节。)
Public API 围绕常见操作(如读取和写入)提供结构化并发封装。 多次调用 API,例如 accept(2)
,它可以随时间返回多个完成,返回 AnyAsyncSequence
。 在内部,封装分配一个 Submission<T>
的具体实例,表示一个初始化的 Submission Queue Entry (SQE),然后将其提交给 io_uring
。 完成处理程序由 libdispatch
监视一个表示可用完成的 eventfd(2)
来处理。 每个队列条目中的 user_data
是一个块,它在环的隔离上下文中执行 Submission<T>
实例的 onCompletion(cqe:)
方法。 必须小心管理事件生命周期中的指针生命周期。
这是一个 TCP echo 服务器的示例,改编自 IORingTCPEcho。
import AsyncExtensions
import IORing
import IORingUtils
let socket = try Socket(ring: IORing.shared, domain: sa_family_t(AF_INET), type: SOCK_STREAM, protocol: 0)
try socket.setReuseAddr()
try socket.setTcpNoDelay()
try socket.bind(port: 10000)
try socket.listen(backlog: 10)
let clients: AnyAsyncSequence<Socket> = try await socket.accept()
for try await client in clients {
Task {
repeat {
let data = try await client.receive(count: bufferSize)
try await client.send(data)
} while true
}
}
更多示例可以在 Examples 中找到。
accept(2)
当然,欢迎提交 pull requests!