当前位置: 首页 > news >正文

目前做啥网站致富哈尔滨建设发展集团有限责任公司

目前做啥网站致富,哈尔滨建设发展集团有限责任公司,开发网站用什么语言好,容桂低价网站建设序列生成器是一个非常经典的协程应用场景,尤其是在需要惰性生成数据或处理潜在无限的数据流时。 序列生成器概念#xff1a;序列生成器允许程序按需生成序列中的下一个元素#xff0c;而不是一次性计算整个序列。这种方式可以节省内存#xff0c;并允许处理无限或未知长度的…序列生成器是一个非常经典的协程应用场景,尤其是在需要惰性生成数据或处理潜在无限的数据流时。 序列生成器概念序列生成器允许程序按需生成序列中的下一个元素而不是一次性计算整个序列。这种方式可以节省内存并允许处理无限或未知长度的数据序列。 实现目标 简单的说序列生成器通常的实现就是在一个协程内部通过某种方式向外部传一个值出去并且将自己挂起外部调用者则可以获取到这个值并且在后续继续恢复执行序列生成器来获取下一个值。 显然挂起和向外部传值的任务就需要通过 co_await 来完成了外部获取值的任务就要通过协程的返回值来完成。 由此程序大致框架如下 Generator sequence() {int i 0;while (true) {co_await i;} }int main() {auto generator sequence();for (int i 0; i 10; i) {std::cout generator.next() std::endl;} }在generator 有个 next 函数调用它时需要想办法让协程恢复执行并将下一个值传出来。 调用者获取值 generator 的类型就是我们即将实现的序列生成器类型 Generator结合上一篇文章当中对于协程返回值类型的介绍我们先大致给出它的定义 struct Generator {struct promise_type {// 开始执行时直接挂起等待外部调用 resume 获取下一个值std::suspend_always initial_suspend() { return {}; };// 执行结束后不需要挂起std::suspend_never final_suspend() noexcept { return {}; }// 为了简单我们认为序列生成器当中不会抛出异常这里不做任何处理void unhandled_exception() { }// 构造协程的返回值类型Generator get_return_object() {return Generator{};}// 没有返回值void return_void() { }};int next() {//这里需要恢复线程} };想要在 Generator 当中 resume 协程的话需要拿到 coroutine_handle。 promise_type 是连接协程内外的桥梁标准库提供了一个通过 promise_type 的对象的地址获取 coroutine_handle 的函数它实际上是 coroutine_handle 的一个静态函数 //vs2022 struct coroutine_handle {constexpr coroutine_handle() noexcept default;constexpr coroutine_handle(nullptr_t) noexcept {}_NODISCARD static coroutine_handle from_promise(_Promise _Prom) noexcept { // strengthenedconst auto _Prom_ptr const_castvoid*(static_castconst volatile void*(_STD addressof(_Prom)));const auto _Frame_ptr __builtin_coro_promise(_Prom_ptr, 0, true);coroutine_handle _Result;_Result._Ptr _Frame_ptr;return _Result;}这样只需要在 get_return_object 函数调用时先获取 coroutine_handle然后再传给即将构造出来的 Generator 即可。 协程内部挂起并传值 观察一下最终实现的效果 Generator sequence() {int i 0;while (true) {co_await i;} }特别需要注意的是 co_await i; 其 后面的是一个整型值而不是在前面的文章当中提到的满足等待体awaiter条件的类型这种情况下该怎么办呢 实际上对于 co_await 表达式当中 expr 的处理C 有一套完善的流程 如果 promise_type 当中定义了 await_transform 函数那么先通过 promise.await_transform(expr) 来对 expr 做一次转换得到的对象称为 awaitable否则 awaitable 就是 expr 本身。 接下来使用 awaitable 对象来获取等待体awaiter。如果 awaitable 对象有 operator co_await 运算符重载那么等待体就是 operator co_await(awaitable)否则等待体就是 awaitable 对象本身。 那么只需要为数据类型实现一个 operator co_await 的运算符重载即可。 struct Generator {struct promise_type {int value;// 传值的同时要挂起值存入 value 当中std::suspend_always await_transform(int value) {this-value value;return {};}};std::coroutine_handlepromise_type handle;int next() {handle.resume();// 外部调用者或者恢复者可以通过读取 valuereturn handle.promise().value;} };定义了 await_transform 函数之后co_await expr 就相当于 co_await promise.await_transform(expr) 了。 协程的销毁 问题1无法确定是否存在下一个元素 当外部调用者或者恢复者试图调用 next 来获取下一个元素的时候它其实并不知道能不能真的得到一个结果。 为了解决这个问题我们需要增加一个 has_next 函数用来判断是否还有新的值传出来has_next 函数调用的时候有两种情况 已经有一个值传出来了还没有被外部消费还没有现成的值可以用需要尝试恢复执行协程来看看还有没有下一个值传出来 struct Generator {bool has_next() {// 协程已经执行完成if (handle.done()) {return false;}// 协程还没有执行完成并且下一个值还没有准备好if (!handle.promise().is_ready) {handle.resume();}if (handle.done()) {// 恢复执行之后协程执行完这时候必然没有通过 co_await 传出值来return false;} else {return true;}}int next() {if (has_next()) {// 此时一定有值is_ready 为 true // 消费当前的值重置 is_ready 为 falsehandle.promise().is_ready false;return handle.promise().value;}throw ExhaustedException();} }; 问题2协程状态的销毁比 Generator 对象的销毁更早 协程的状态在协程体执行完之后就会销毁除非协程挂起在 final_suspend 调用时。为了让协程的状态的生成周期与 Generator 一致在Generator可能会使用导协程状态我们必须将协程的销毁交给 Generator 来处理 struct Generator {class ExhaustedException: std::exception { };struct promise_type {// 总是挂起让 Generator 来销毁std::suspend_always final_suspend() noexcept { return {}; }};~Generator() {// 销毁协程handle.destroy();} };问题3复制对象导致协程被销毁 在 Generator 的析构函数当中销毁协程这本身没有什么问题。但如果把 Generator 对象做一下复制 Generator returns_generator() {auto g sequence();if (g.has_next()) {std::cout g.next() std::endl;}return g; }由于把 g 当做返回值返回了这时候 g 这个对象就发生了一次复制然后临时对象被销毁协程也就没了再调用直接dump。 为了解决这个问题需要妥善地处理 Generator 的复制构造器 struct Generator {explicit Generator(std::coroutine_handlepromise_type handle) noexcept: handle(handle) {}Generator(Generator generator) noexcept: handle(std::exchange(generator.handle, {})) {}Generator(Generator ) delete;Generator operator(Generator ) delete;~Generator() {if (handle) handle.destroy();} }只提供了右值复制构造器对于左值复制构造器我们直接删除掉以禁止使用。原因也很简单对于每一个协程实例都有且仅能有一个 Generator 实例与之对应因此我们只支持移动对象而不支持复制对象。 序列生成器完整实现 #include coroutine #include exception #include iostream #include threadstruct Generator {class ExhaustedException : std::exception { };struct promise_type {int value;bool is_ready false;std::suspend_always initial_suspend() { return {}; };std::suspend_always final_suspend() noexcept { return {}; }std::suspend_always await_transform(int value) {this-value value;is_ready true;return {};}void unhandled_exception() {}Generator get_return_object() {return Generator{ std::coroutine_handlepromise_type::from_promise(*this) };}void return_void() { }};std::coroutine_handlepromise_type handle;bool has_next() {if (handle.done()) {return false;}if (!handle.promise().is_ready) {handle.resume();//让协程恢复执行}if (handle.done()) {return false;}else {return true;}}int next() {if (has_next()) {handle.promise().is_ready false;return handle.promise().value;}throw ExhaustedException();}explicit Generator(std::coroutine_handlepromise_type handle) noexcept: handle(handle) {}Generator(Generator generator) noexcept: handle(std::exchange(generator.handle, {})) {}Generator(Generator) delete;Generator operator(Generator) delete;~Generator() {if (handle) handle.destroy();} };Generator sequence() {int i 0;while (i 5) {co_await i;} }Generator returns_generator() {auto g sequence();if (g.has_next()) {std::cout g.next() std::endl;}return g; }int main() {auto generator returns_generator();for (int i 0; i 15; i) {if (generator.has_next()) {std::cout generator.next() std::endl;}else {break;}}return 0; }使用 co_yield C 当中的 co_yield expr 等价于 co_await promise.yield_value(expr)我们只需要将前面例子当中的 await_transform 函数替换成 yield_value 就可以使用 co_yield 来传值了 std::suspend_always yield_value(int value) {this-value value;is_ready true;return {};}通常情况下使用 co_await 更多的关注点在挂起自己等待别人上而使用 co_yield 则是挂起自己传值出去。 使用序列生成器生成斐波那契数列 Generator fibonacci() {co_await 0; // fib(0)co_await 1; // fib(1)int a 0;int b 1;while (true) {co_await (a b); // fib(N), N 1b a b;a b - a;} }int main() {auto generator fibonacci();for (int i 0; i 15; i) {if (generator.has_next()) {std::cout generator.next() std::endl;}else {break;}}return 0; }fibonacci()通过连续的 co_await 表达式生成斐波那契数列的值。首先固定地生成 0 和 1然后进入循环不断计算后续数值并通过 co_await 暂停和恢复协程以生成数列。 协程的启动和恢复是通过 Generator::has_next 和 Generator::next 中的 handle.resume() 来控制的。 每次 co_await 在 fibonacci 中被调用时协程暂停并在 await_transform 中处理新的值。 当 co_await 后的表达式执行完毕后协程在 await_transform 返回的挂起点恢复。
http://www.w-s-a.com/news/614888/

相关文章:

  • 最简单的网站系统昨天军事新闻最新消息
  • 做ps网页设计的网站有哪些wordpress内容付费
  • 有没有免费注册域名的网站科技小制作 手工 简单
  • 网站支付端口win10优化大师怎么样
  • 怎么做云购网站吗网站流量监测
  • 网站被恶意刷流量可以翻外墙的浏览器
  • 网站做直链下载存储解决方案怎么把网站设置为主页面
  • 西安做网站招聘深圳网站见
  • 网站怎么做优化百度能搜索到wordpress 子分类
  • 六安网站建设培训制作网站需要多少时间
  • 电子商务专业网站建设什么软件可以做动画视频网站
  • wordpress 分享主题做网站优化有必要
  • ftp 网站管理电商网站设计图片
  • 惠州免费建站模板营销型旅游网站建设
  • 南宁cms建站wordpress 开启缩略图
  • 网站模板软件网站admin密码
  • 网站信息做参考文献射阳做企业网站多少钱
  • 网站外部优化的4大重点外贸站外推广
  • 宁波网站建设活动德州乐陵德州seo公司
  • 网站网址相对路径如何设置wordpress怎么加快网站打开速度
  • 有没有能帮人快速网站备案的机构网站建设与制作总结
  • 网站不用了怎么办苏州h5模板建站
  • 网站建设制作定制免费网络短剧
  • 建设部建造师强制注销网站h5响应式网站模板下载
  • 蛋糕网站内容规划建设网站需要多少钱济南兴田德润o厉害吗
  • 企业如何建设网站呢做网站的高手
  • 为什么打开网址都是站长工具开发一款网站需要多少钱
  • 做一个网站app需要多少钱分类信息网站建设计划
  • 怎样下载建设部网站建模培训
  • 北流网站建设制作旅游网站开发目的和目标