Skip to content

异步 I/O

现代应用程序的性能瓶颈往往在于 I/O(输入/输出)操作,如读写文件、访问数据库或进行网络通信。传统的同步 I/O 会阻塞整个线程,直到操作完成,这极大地浪费了 CPU 资源并降低了应用的吞吐量。

koroutine_lib 提供了一个强大的、跨平台的异步 I/O 模块——async_io,它将底层复杂的系统调用(如 io_uring, kqueue, IOCP)封装在统一、简洁的协程接口之后。

1. IOEngine: 异步 I/O 的心脏

IOEngineasync_io 模块的核心。它是一个在后台运行的事件循环,专门负责监听 I/O 事件。当一个异步 I/O 操作被发起时,它并不会阻塞当前协程,而是将这个操作注册到 IOEngine。当前协程会挂起,IOEngine 则在后台等待操作系统通知该操作完成。一旦完成,IOEngine 会负责唤醒之前挂起的协程。

koroutine_lib 会根据操作系统自动选择最高效的 IOEngine 实现: - Linux: IoUringIOEngine (基于 io_uring) - macOS/BSD: KqueueIOEngine (基于 kqueue) - Windows: IOCPIOEngine (基于 IOCP)

你通常不需要直接与 IOEngine 交互,SchedulerManager 会为你管理一个默认的 I/O 调度器。

2. 异步文件操作: AsyncFile

AsyncFile 提供了对文件进行异步读写的能力。

打开文件

使用 async_io::async_open 工厂函数来异步地打开一个文件。它返回一个 Task<std::shared_ptr<AsyncFile>>

#include "koroutine/async_io/async_io.hpp"

Task<void> main_task() {
    // 异步打开文件用于写入,如果不存在则创建
    auto file = co_await async_io::async_open("my_file.txt", std::ios::out | std::ios::trunc);
    // ...
}

读写文件

AsyncFile 继承自 AsyncIOObject,提供了 readwrite 方法。

  • co_await file->write(buffer, size): 异步写入数据。
  • size_t bytes_read = co_await file->read(buffer, size): 异步读取数据。

示例:异步读取并写入文件

下面的例子展示了如何异步地将一个文件的内容复制到另一个文件。

#include "koroutine/async_io/async_io.hpp"
#include <vector>
#include <iostream>

Task<void> async_copy_file(const std::string& src_path, const std::string& dest_path) {
    try {
        auto src_file = co_await async_io::async_open(src_path, std::ios::in);
        auto dest_file = co_await async_io::async_open(dest_path, std::ios::out | std::ios::trunc);

        std::vector<char> buffer(4096);
        while (true) {
            // 异步读取源文件
            size_t bytes_read = co_await src_file->read(buffer.data(), buffer.size());
            if (bytes_read == 0) {
                break; // 文件读取完毕
            }
            // 异步写入目标文件
            co_await dest_file->write(buffer.data(), bytes_read);
        }
        std::cout << "文件复制成功!" << std::endl;
    } catch (const std::system_error& e) {
        std::cerr << "文件操作失败: " << e.what() << std::endl;
    }
}

int main() {
    // 确保你的程序启动了 IO 调度器
    SchedulerManager::create_io_scheduler();
    Runtime::block_on(async_copy_file("input.txt", "output.txt"));
}

3. 异步网络操作: AsyncSocket

AsyncSocket 提供了进行异步网络编程的能力,包括建立连接、发送和接收数据。

建立连接

使用 async_io::async_connect 来异步地连接到一个 TCP 服务器。

Task<void> connect_to_server() {
    try {
        // 异步连接到本地 8080 端口
        auto socket = co_await async_io::async_connect("127.0.0.1", 8080);
        std::cout << "成功连接到服务器!" << std::endl;
        // ...
    } catch (const std::system_error& e) {
        std::cerr << "连接失败: " << e.what() << std::endl;
    }
}

示例:一个简单的 HTTP 客户端

下面是一个使用 AsyncSocket 异步发送一个 HTTP GET 请求并接收响应的例子。

#include "koroutine/async_io/async_io.hpp"
#include <vector>
#include <iostream>

Task<void> http_get_example(const std::string& host, uint16_t port, const std::string& path) {
    try {
        auto socket = co_await async_io::async_connect(host, port);
        std::cout << "成功连接到 " << host << std::endl;

        std::string request = "GET " + path + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n";

        // 异步发送请求
        co_await socket->write(request.c_str(), request.length());
        std::cout << "HTTP 请求已发送" << std::endl;

        std::vector<char> response_buffer(4096);
        // 异步接收响应
        size_t bytes_read = co_await socket->read(response_buffer.data(), response_buffer.size() - 1);

        response_buffer[bytes_read] = '\0'; // 添加 null 终止符
        std::cout << "\n收到响应:\n" << response_buffer.data() << std::endl;

    } catch (const std::system_error& e) {
        std::cerr << "HTTP 请求失败: " << e.what() << std::endl;
    }
}

int main() {
    SchedulerManager::create_io_scheduler();
    Runtime::block_on(http_get_example("example.com", 80, "/"));
}

通过 async_io 模块,你可以用同步风格的代码编写出高性能的、完全非阻塞的 I/O 密集型应用程序,例如网络爬虫、HTTP 服务器、数据库代理等。