C++并发之协程实例(二)(计算斐波那契序列)

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
异常: 太大斐波那契序列,元素将会溢出
  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnow010

你的鼓励就是我最大的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值