目录
- 1 协程
- 2 实例-计算斐波那契序列
- 2.1 斐波那契序列
- 2.2 代码
- 3 运行
1 协程
协程(Coroutines)是一个可以挂起执行以便稍后恢复的函数。协程是无堆栈的:它们通过返回到调用方来暂停执行,并且恢复执行所需的数据与堆栈分开存储。这允许异步执行的顺序代码(例如,在没有显式回调的情况下处理非阻塞I/O),还支持惰性计算无限序列上的算法和其他用途。
协程类图如下:
2 实例-计算斐波那契序列
2.1 斐波那契序列
斐波那契数列是一位意大利的数学家,他闲着没事去研究兔子繁殖的过程,研究着就发现,可以写成这么一个序列:1,1,2,3,5,8,13,21… 也就是每个数等于它前两个数之和。那么给你第 n 个数,问 F (n) 是多少。
用数学公式表示很简单: f(n) = f(n-1) + f(n-2)
下面的例子使用协程来计算斐波那契序列
2.2 代码
#include <coroutine>
#include <cstdint>
#include <exception>
#include <iostream>
template <typename T>
struct Generator
{
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
struct promise_type
{
T value_;
std::exception_ptr exception_;
Generator get_return_object()
{
return Generator(handle_type::from_promise(*this));
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void unhandled_exception() { exception_ = std::current_exception(); }
template<std::convertible_to<T> From>
std::suspend_always yield_value(From&& from)//设置完值后挂起协程
{
value_ = std::forward<From>(from);
return {};
}
void return_void() {}
};
handle_type h_;
Generator(handle_type h) : h_(h) {}
~Generator() { h_.destroy(); }
explicit operator bool()
{
fill();
return !h_.done();
}
T operator()()
{
fill();
full_ = false;
return std::move(h_.promise().value_);
}
private:
bool full_ = false;
void fill()
{
if(!full_)
{
h_();//
if(h_.promise().exception_)
std::rethrow_exception(h_.promise().exception_);
full_ = true;
}
}
};
Generator<std::uint64_t>
fibonacci_sequence(unsigned n)//斐波那契序列
{
if(n == 0)
co_return;//计算结束
if(n > 94)
throw std::runtime_error("太大斐波那契序列,元素将会溢出");
co_yield 0;//挂起协程
if(n == 1)
co_return;//计算结束
co_yield 1;
if(n == 2)
co_return;
std::uint64_t a = 0;
std::uint64_t b = 1;
for(unsigned i = 2; i < n; ++i)
{
std::uint64_t s = a + b;
co_yield s;//挂起协程
a = b;
b = s;
}
//计算结束
}
int main(int argc, char *argv[])
{
int n = 10;
if(argc > 1)
n = std::stoul(argv[1]);
try
{
auto gen = fibonacci_sequence(n);
for(int j = 0; gen; ++j)//调用operator bool()判断是gen是否计算结束
std::cout << "fib(" << j << ")=" << gen() << std::endl;//调用T operator()()返回计算j对应的斐波那契序列值
}
catch(const std::exception& e)
{
std::cerr << "异常: " << e.what() << std::endl;
}
catch(...)
{
std::cerr << "未知异常\n";
}
return 0;
}
3 运行
$./example2 0
$./example2 0 1
fib(0)=0
$./example2 0 4
fib(0)=0
fib(1)=1
fib(2)=1
fib(3)=2
$./example2 0 10
fib(0)=0
fib(1)=1
fib(2)=1
fib(3)=2
fib(4)=3
fib(5)=5
fib(6)=8
fib(7)=13
fib(8)=21
fib(9)=34
$./example2 95
异常: 太大斐波那契序列,元素将会溢出