co_yield 是 C++20 协程(coroutines)特性中的一个关键字,主要用于实现生成器或惰性求值序列。它解决的核心问题是:如何以简洁、高效、可读的方式编写可以暂停和恢复执行的函数,从而按需产生一系列值。
生成器是一种特殊的函数,它不会一次性计算并返回所有结果,而是能够在每次被请求时产出一个值,然后暂停执行,等到下一次被调用时再从上次暂停的地方继续运行。这种方式非常适合处理大量数据或理论上无限的序列,因为它避免了提前将所有数据加载到内存中,从而显著节省资源。
惰性求值序列则是指一种按需计算的策略:序列中的每个元素只有在真正被使用时才会被计算出来,而不是在序列创建之初就全部生成。这种延迟计算的方式不仅提高了效率,还使得处理超大甚至无限的数据流成为可能。在 C++20 中,通过 co_yield 实现的协程正是构建生成器和惰性求值序列的现代工具,让开发者能以清晰、线性的代码风格写出高效、低内存开销的数据生产逻辑。
1. 问题场景
#include <iostream>
int fibonacci()
{
static int prev1 = 0;
static int prev2 = 1;
int current = prev1;
int next = prev1 + prev2;
prev1 = prev2;
prev2 = next;
return current;
}
void demo()
{
int val = fibonacci();
std::cout << val << std::endl;
val = fibonacci();
std::cout << val << std::endl;
val = fibonacci();
std::cout << val << std::endl;
val = fibonacci();
std::cout << val << std::endl;
val = fibonacci();
std::cout << val << std::endl;
val = fibonacci();
std::cout << val << std::endl;
val = fibonacci();
std::cout << val << std::endl;
}
int main()
{
demo();
return 0;
}
2. 解决方法
#include <iostream>
#include <coroutine>
struct Generator
{
// 协程执行规则定义
struct promise_type
{
int value;
// 创建协程操作管理对象
Generator get_return_object()
{
return Generator{ std::coroutine_handle<promise_type>::from_promise(*this) };
}
// 决定协程创建后是否马上挂起
std::suspend_always initial_suspend()
{
return {};
}
// 最终挂起:执行完后不立即销毁
// std::suspend_never:不挂起,立即销毁资源
// std::suspend_always:挂起,不立即销毁,等待外部 destroy 释放资源
std::suspend_never final_suspend() noexcept
{
return {};
}
// 核心:处理co_yield(暂停并保存值)
// std::suspend_never:不挂起
// std::suspend_always:挂起
std::suspend_always yield_value(int value)
{
this->value = value;
return {};
}
// 协程结束时的动作
void return_void()
{
std::cout << "协程结束" << std::endl;
}
// 异常未处理时的动作
void unhandled_exception()
{
std::terminate();
}
};
// 协程实际操作执行
std::coroutine_handle<promise_type> handle;
explicit Generator(std::coroutine_handle<promise_type> handle)
{
this->handle = handle;
}
// 获取下一个值(返回是否有值)
bool next()
{
// 协程的执行状态:
// true: 协程已完成,无法再通过 resume() 恢复执行
// false: 协程处于挂起态,可以通过 resume() 恢复执行
if (handle.done())
{
return false;
}
// 恢复协程执行
handle.resume();
// 返回协程状态
return !handle.done();
}
// 获取当前值
int value() const
{
return handle.promise().value;
}
~Generator()
{
if (handle)
{
handle.destroy();
}
}
};
Generator fibonacci()
{
int prev1 = 0;
int prev2 = 1;
while (true)
{
int current = prev1;
int next = prev1 + prev2;
prev1 = prev2;
prev2 = next;
co_yield current;
}
}
void demo()
{
// 创建协程
auto gen = fibonacci();
for (int i = 0; i < 10; ++i)
{
// 恢复协程
bool flag = gen.next();
if (!flag)
{
break;
}
// 获得数值
std::cout << gen.value() << std::endl;
}
}
int main()
{
demo();
return 0;
}

冀公网安备13050302001966号