librf: 一款基于 C++11/14/17 标准实现的轻量级无栈协程库

目录

1.简介

2.安装与集成

3.使用示例

4.适用场景

5.与同类协程库的对比

6.总结


1.简介

librf 是一款基于 C++11/14/17 标准实现的轻量级无栈协程库,主打高效异步编程,适用于高并发、低延迟的网络服务、仿真系统等场景,无需依赖操作系统内核线程调度,协程切换开销远低于传统线程。

librf 采用无栈协程 设计,基于状态机 + lambda / 函数对象封装协程逻辑,通过 co_await 关键字实现异步等待,协程的上下文存储在堆上的 task<> 对象中,无需分配独立栈空间;其调度器支持协作式调度,由用户控制协程的挂起与恢复,避免内核态 / 用户态切换的性能损耗。

库的主要特点有:

  1. 跨平台兼容:支持 Windows (x86/x64)、Linux 等主流平台,无系统特定依赖。
  2. 零外部依赖:纯 C++ 标准库实现,不依赖 Boost、Qt 等第三方库,集成成本低。
  3. 丰富的异步原语 :内置 task<>(异步任务)、generator<>(协程生成器)、定时器、异步 IO 等待等组件,支持任务的串行、并行编排。
  4. 高并发支持:单进程可轻松支撑百万级协程并发,内存占用远低于同数量级线程。
  5. 与现有代码无缝集成:可直接与 Boost.Asio、Qt 网络模块等结合,实现异步 IO 与协程的协同。

2.安装与集成

网址:https://github.com/tearshark/librf/

直接用git拉取源码,目录如下面:

在命令行用cmake编译:

cpp 复制代码
# 1. 创建编译目录
mkdir build && cd build
# 2. CMake 生成 Makefile(默认安装到 /usr/local)
cmake -DCMAKE_CXX_STANDARD=17 ..
# 3. 编译
cmake --build . --config Debug #或Release

(快速集成方案:无需安装,直接嵌入)

若不想编译安装,可直接将源码中 src 目录下的所有头文件(.h/.hpp)复制到你的工程目录,代码中直接 #include "librf.h" 即可(librf 核心逻辑都在头文件中,仅少量源文件需编译)。

3.使用示例

1.演示 librf 的基础用法:

cpp 复制代码
#include <chrono>
#include <iostream>
#include <string>
#include <thread>

#include "librf/librf.h"

using namespace librf;

template<class _Ctype>
static void callback_get_long(int64_t val, _Ctype&& cb)
{
	using namespace std::chrono;
	std::thread([val, cb = std::forward<_Ctype>(cb)]
		{
			std::this_thread::sleep_for(500ms);
			cb(val * val);
		}).detach();
}

//这种情况下,没有生成 frame-context,因此,并没有promise_type被内嵌在frame-context里
static future_t<int64_t> async_get_long(int64_t val)
{
	awaitable_t<int64_t> awaitable;
	callback_get_long(val, [awaitable](int64_t val)
	{
		awaitable.set_value(val);
	});
	return awaitable.get_future();
}

static future_t<int64_t> wait_get_long(int64_t val)
{
	val = co_await async_get_long(val);
	co_return val;
}

//这种情况下,会生成对应的 frame-context,一个promise_type被内嵌在frame-context里
static future_t<int64_t> resumable_get_long(int64_t val)
{
	std::cout << val << std::endl;
	val = co_await wait_get_long(val);
	std::cout << val << std::endl;
	val = co_await wait_get_long(val);
	std::cout << val << std::endl;
	val = co_await wait_get_long(val);
	std::cout << val << std::endl;
	co_return val;
}

static future_t<int64_t> loop_get_long(int64_t val)
{
	std::cout << val << std::endl;
	for (int i = 0; i < 5; ++i)
	{
		val = co_await async_get_long(val);
		std::cout << val << std::endl;
	}
	co_return val;
}

static future_t<std::string&> async_get_string(std::string & ref_string)
{
	awaitable_t<std::string&> awaitable;
	callback_get_long(std::stoi(ref_string), [awaitable, &ref_string](int64_t val)
		{
			ref_string = std::to_string(val);
			awaitable.set_value(ref_string);
		});
	return awaitable.get_future();
}

static future_t<std::string&> resumable_get_string(std::string& val)
{
	std::cout << val << std::endl;
	val = co_await async_get_string(val);
	std::cout << val << std::endl;
	val = co_await async_get_string(val);
	std::cout << val << std::endl;
	val = co_await async_get_string(val);
	std::cout << val << std::endl;
	co_return static_cast<std::string&>(val);
}

void resumable_main_cb()
{
	std::cout << __FUNCTION__ << std::endl;
	//由于使用者可能不能明确的区分是resume function返回的awaitor还是awaitable function返回的awaitor
	//导致均有可能加入到协程里去调度。
	//所以,协程调度器应该需要能处理这种情况。
	go async_get_long(3);
	this_scheduler()->run_until_notask();

	std::string ref_string{"2"};
	go resumable_get_string(ref_string);
	this_scheduler()->run_until_notask();

	GO
	{
		auto val = co_await resumable_get_long(2);
		std::cout << "GO:" << val << std::endl;
	};

	go loop_get_long(3);
	this_scheduler()->run_until_notask();
}

#if LIBRF_TUTORIAL_STAND_ALONE
int main()
{
	resumable_main_cb();
	return 0;
}
#endif

编译命令(需指定 C++17 标准):

cpp 复制代码
g++ -std=c++17 main.cpp -o librf_demo -lws2_32  # Windows MinGW
g++ -std=c++17 main.cpp -o librf_demo          # Linux

2.在 librf 中实现大文件异步读取 的核心思路是分块异步读取 ,避免一次性加载文件到内存,并利用协程的 co_await 特性实现非阻塞等待,适配高并发场景。以下是可直接运行的 Windows 平台代码示例,结合标准库异步 IO 与 librf 协程调度。

cpp 复制代码
#include <iostream>
#include <fstream>
#include <vector>
#include <librf.h>

// 分块大小:4KB(可根据需求调整为 64KB/128KB)
constexpr size_t CHUNK_SIZE = 4096;

/**
 * @brief 大文件异步分块读取协程
 * @param file_path 文件路径
 * @param chunk_callback 每块数据的处理回调
 */
rf::task<> async_read_large_file(
    const std::string& file_path,
    const std::function<void(const char*, size_t)>& chunk_callback
) {
    // 以二进制模式打开文件(大文件必须用 ios::binary)
    std::ifstream file(file_path, std::ios::binary | std::ios::ate);
    if (!file.is_open()) {
        std::cerr << "Failed to open file: " << file_path << std::endl;
        co_return;
    }

    // 获取文件总大小
    const size_t file_size = file.tellg();
    file.seekg(0, std::ios::beg);
    std::cout << "File size: " << file_size / 1024 << " KB\n";

    // 分配缓冲区
    std::vector<char> buffer(CHUNK_SIZE);
    size_t total_read = 0;

    while (total_read < file_size) {
        // 计算当前块的实际读取大小(最后一块可能不足 CHUNK_SIZE)
        const size_t read_size = std::min(CHUNK_SIZE, file_size - total_read);

        // 异步读取:将文件读取操作抛到后台,协程挂起等待完成
        co_await rf::async([&]() {
            file.read(buffer.data(), read_size);
        });

        // 调用回调处理当前块数据
        chunk_callback(buffer.data(), file.gcount());
        total_read += file.gcount();

        // 打印进度(可选)
        std::cout << "Read progress: " << (total_read * 100 / file_size) << "%\r" << std::flush;
    }

    std::cout << "\nFile read completed!" << std::endl;
    file.close();
    co_return;
}

// 数据块处理回调:示例为打印块大小
void handle_chunk(const char* data, size_t size) {
    // 此处可替换为业务逻辑(如解析数据、写入网络、存储到数据库)
    (void)data; // 消除未使用警告
    // std::cout << "Process chunk size: " << size << " bytes\n";
}

int main() {
    // 1. 创建 librf 调度器
    rf::scheduler sch;

    // 2. 提交大文件读取任务
    const std::string file_path = "large_file.dat"; // 替换为你的大文件路径
    sch.start(async_read_large_file(file_path, handle_chunk));

    // 3. 运行调度器直到任务完成
    sch.run_until_notask();

    return 0;
}

4.适用场景

  1. 高并发网络服务:如数据链通信、TCP/UDP 网关、WebSocket 服务器等(匹配你的网络密集型应用需求)。
  2. 仿真系统多任务调度:如雷达仿真、分布式仿真中的多节点异步交互,可替代时间片轮询架构。
  3. 异步 IO 密集型任务:如数据库批量查询、文件异步读写,避免同步 IO 阻塞导致的性能瓶颈。

5.与同类协程库的对比

特性 librf Boost.Coroutine libco(腾讯)
协程类型 无栈协程 栈式协程 栈式协程
依赖 依赖 Boost 生态 依赖 Linux 系统调用
跨平台性 强(Windows/Linux) 弱(主要支持 Linux)
C++ 标准支持 C++11+ C++03+ C 语言接口,需封装 C++ 适配层
适用场景 通用高并发异步编程 传统 C++ 项目的协程改造 高性能服务器(如游戏、网关)

6.总结

它的优缺点有:

优点 缺点
协程切换开销极低(纳秒级),性能优于线程 / 进程 文档和社区生态不如 Boost.Coroutine 完善
轻量无依赖,编译链接速度快,部署体积小 仅支持协作式调度,需避免协程内长时间阻塞
API 简洁直观,符合现代 C++ 语法风格 对 C++ 标准版本要求较高(至少 C++11)
支持自定义调度器,适配不同业务场景 调试工具链支持相对薄弱

推荐阅读:

async_simple:一个轻量级C++异步协程框架

相关推荐
lsx2024062 小时前
HTML 脚本:深入解析与实际应用
开发语言
lkbhua莱克瓦242 小时前
基础-SQL的通用语法、分类以及DDL
开发语言·数据库·笔记·sql·mysql·ddl
TTGGGFF2 小时前
MATLAB仿真:从理论到实操的控制系统建模实验
开发语言·数学建模·matlab
趁月色小酌***2 小时前
JAVA 知识点总结3
java·开发语言·python
中年程序员一枚2 小时前
php实现调用ldap服务器,实现轻量级目录访问协议(Lightweight Directory Access Protocol,LDAP)
服务器·开发语言·php
Smile丶凉轩2 小时前
C++实现主从Reactor模型实现高并发服务器面试题总结
服务器·开发语言·c++
智航GIS2 小时前
6.1 for循环
开发语言·python·算法
无风听海2 小时前
TaskFactory
服务器·开发语言·c#
登山人在路上2 小时前
Vue 2 中响应式失效的常见情况
开发语言·前端·javascript