目录
1.简介
librf 是一款基于 C++11/14/17 标准实现的轻量级无栈协程库,主打高效异步编程,适用于高并发、低延迟的网络服务、仿真系统等场景,无需依赖操作系统内核线程调度,协程切换开销远低于传统线程。
librf 采用无栈协程 设计,基于状态机 + lambda / 函数对象封装协程逻辑,通过 co_await 关键字实现异步等待,协程的上下文存储在堆上的 task<> 对象中,无需分配独立栈空间;其调度器支持协作式调度,由用户控制协程的挂起与恢复,避免内核态 / 用户态切换的性能损耗。
库的主要特点有:
- 跨平台兼容:支持 Windows (x86/x64)、Linux 等主流平台,无系统特定依赖。
- 零外部依赖:纯 C++ 标准库实现,不依赖 Boost、Qt 等第三方库,集成成本低。
- 丰富的异步原语 :内置
task<>(异步任务)、generator<>(协程生成器)、定时器、异步 IO 等待等组件,支持任务的串行、并行编排。 - 高并发支持:单进程可轻松支撑百万级协程并发,内存占用远低于同数量级线程。
- 与现有代码无缝集成:可直接与 Boost.Asio、Qt 网络模块等结合,实现异步 IO 与协程的协同。
2.安装与集成
直接用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.适用场景
- 高并发网络服务:如数据链通信、TCP/UDP 网关、WebSocket 服务器等(匹配你的网络密集型应用需求)。
- 仿真系统多任务调度:如雷达仿真、分布式仿真中的多节点异步交互,可替代时间片轮询架构。
- 异步 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) |
| 支持自定义调度器,适配不同业务场景 | 调试工具链支持相对薄弱 |
推荐阅读: