解锁 Rust 异步编程:深入探索 Mio 库的高效 I/O 之道

文摘   2024-07-16 00:02   江苏  

前言:

在现代软件开发中,性能和效率是衡量应用成功的关键指标。Rust 语言以其安全性、速度和内存管理能力而闻名,而 Mio 库则是 Rust 生态系统中的一颗璀璨明珠,专为追求极致性能的开发者设计。本文将带您深入了解 Mio,一个专注于非阻塞 API 和事件通知的低层次 I/O 库,探索如何利用它构建高性能的 I/O 应用程序。

解锁 Rust 异步编程:深入探索 Mio 库的高效 I/O 之道

Mio 是 Rust 的一个快速、低层次的 I/O 库,专注于非阻塞 API 和事件通知,用于构建尽可能减少操作系统抽象开销的高性能 I/O 应用程序。

API 文档

  • v1[1]
  • v0.8[2]

这是一个低层次库,如果您正在寻找更易于上手的东西,请看 Tokio[3]

使用方法

要使用 mio,请先将其添加到您的 Cargo.toml 中:

[dependencies]
mio = "1"

接下来,我们可以开始使用 Mio。以下是使用 TcpListenerTcpStream 的快速介绍。注意,此示例必须指定 features = ["os-poll", "net"]

use std::error::Error;

use mio::net::{TcpListener, TcpStream};
use mio::{Events, Interest, Poll, Token};

// 一些令牌,以便我们识别哪个事件对应哪个套接字。
const SERVER: Token = Token(0);
const CLIENT: Token = Token(1);

fn main() -> Result<(), Box<dyn Error>> {
    // 创建一个轮询实例。
    let mut poll = Poll::new()?;
    // 为事件创建存储空间。
    let mut events = Events::with_capacity(128);

    // 设置服务器套接字。
    let addr = "127.0.0.1:13265".parse()?;
    let mut server = TcpListener::bind(addr)?;
    // 开始监听传入连接。
    poll.registry()
        .register(&mut server, SERVER, Interest::READABLE)?;

    // 设置客户端套接字。
    let mut client = TcpStream::connect(addr)?;
    // 注册套接字。
    poll.registry()
        .register(&mut client, CLIENT, Interest::READABLE | Interest::WRITABLE)?;

    // 开始事件循环。
    loop {
        // 轮询 Mio 事件,阻塞直到我们收到一个事件。
        poll.poll(&mut events, None)?;

        // 处理每个事件。
        for event in events.iter() {
            // 我们可以使用我们之前提供给 `register` 的令牌来确定事件是针对哪个套接字。
            match event.token() {
                SERVER => {
                    // 如果这是服务器的事件,这意味着连接已经准备好被接受。
                    //
                    // 接受连接并立即丢弃。这将关闭套接字并通知客户端 EOF。
                    let connection = server.accept();
                    drop(connection);
                }
                CLIENT => {
                    if event.is_writable() {
                        // 我们可以(可能)在不阻塞的情况下写入套接字。
                    }

                    if event.is_readable() {
                        // 我们可以(可能)在不阻塞的情况下从套接字读取。
                    }

                    // 由于服务器刚刚关闭了连接,让我们从事件循环中退出。
                    return Ok(());
                }
                // 我们不期望任何除了我们提供的令牌之外的事件。
                _ => unreachable!(),
            }
        }
    }
}

特性

  • 非阻塞 TCP、UDP、UDS
  • 由 epoll、kqueue 和 IOCP 支持的 I/O 事件队列
  • 运行时零分配
  • 平台特定的扩展

非目标

以下是明确从 Mio 中省略的,留给用户或更高层次的库。

  • 文件操作
  • 线程池 / 多线程事件循环
  • 计时器

平台

当前支持的平台:

  • Android(API 级别 21)
  • DragonFly BSD
  • FreeBSD
  • Linux
  • NetBSD
  • OpenBSD
  • Windows
  • iOS
  • macOS

Mio 可以处理与上述平台的事件系统的接口。它们的实现细节在 API 文档中的 Poll 类型中进一步讨论(见上文)。

Mio 通常支持与 Rust 语言(rustc)相同的上述平台版本,除非另有说明。

Windows 用于轮询套接字的实现使用的是 [wepoll] 策略。这使用 Windows AFD 系统访问套接字就绪事件。

不支持

  • Wine,见 问题 #1444

MSRV 政策

MSRV(最小支持的 Rust 版本)对于给定的小版本(1.x)是固定的。然而,在提升小版本时可以增加 MSRV,例如从 1.0 升级到 1.1 允许我们增加 MSRV。无法增加 Rust 版本的用户可以使用旧的小版本。以下是 Mio 版本及其 MSRV 的列表:

  • v0.8: Rust 1.46。
  • v1.0: Rust 1.70。

但请注意,Mio 也有依赖项,它们可能有不同的 MSRV 政策。我们尝试在更新依赖项时坚持上述政策,但这并不总是可能的。

不支持的标志

Mio 使用不同的实现来支持相同的功能,这取决于平台。Mio 通常使用“最佳”实现,其中“最佳”通常意味着对 Mio 的用例最有效。然而,这意味着实现通常是特定于有限数量的平台,这意味着我们经常有多个实现相同的功能。在某些情况下,可能需要不使用“最佳”实现,而是 Mio 支持的另一种实现(在其他平台上)。Mio 官方不支持平台上的次要实现,但我们确实有各种 cfg 标志来强制使用这些情况下的另一种实现。

当前标志:

  • mio_unsupported_force_poll_poll,使用基于 poll(2) 的实现为 mio::Poll
  • mio_unsupported_force_waker_pipe,使用基于 pipe(2) 的实现为 mio::Waker

再次强调,Mio 官方不支持这一点。此外,这些标志将来可能会消失。

社区

一群 Mio 用户在 [Discord] 上闲逛,这可能是提问的好地方。也可以在 GitHub 上打开新问题 来提问、报告错误或建议新功能。

参考资料
[1]

v1: https://docs.rs/mio/^1

[2]

v0.8: https://docs.rs/mio/^0.8

[3]

Tokio: https://tokio.rs


编程悟道
自制软件研发、软件商店,全栈,ARTS 、架构,模型,原生系统,后端(Node、React)以及跨平台技术(Flutter、RN).vue.js react.js next.js express koa hapi uniapp Astro
 最新文章