营销方案 网站网页代码转wordpress
- 作者: 五速梦信息网
- 时间: 2026年04月20日 06:59
当前位置: 首页 > news >正文
营销方案 网站,网页代码转wordpress,高新技术企业网站怎么做,浙江省住房和城乡建设厅网站 文件文章目录 什么是协程为什么需要协程什么时候使用协程协程的类别C20的协程协程的使用关键字co_wait框架一阶段完成数据交换co_yieldco_return 什么是协程 我们在学习编程的过程中#xff0c;逐渐从单线程#xff0c;到多线程#xff0c;再到异步编程和并发处理 这些异步与并… 文章目录 什么是协程为什么需要协程什么时候使用协程协程的类别C20的协程协程的使用关键字co_wait框架一阶段完成数据交换co_yieldco_return 什么是协程 我们在学习编程的过程中逐渐从单线程到多线程再到异步编程和并发处理 这些异步与并发的任务不断增加导致回调结构会变得复杂为了提高代码的可读性和可维护性协程Coroutine就被引入了 用来简化整个过程的操作 协程是一种特殊的函数可以在中途暂停并在稍后恢复执行 与线程不同协程不会占用独立的系统资源而是可以由程序直接控制何时暂停和恢复 因此协程其实就是属于某个具体的线程的可以理解为一个单独的函数一个单独的执行流好处就是没有线程的上下文切换的消耗协程的调度也是自行实现的会更加灵活 为什么需要协程 简单理解的话可以理解为虽然线程已经能够完成绝大部分的任务了但是线程的粒度还不够精细 举个例子 在网络中我们调用read函数读取数据如果缓冲区没有数据的话整个线程就会一直阻塞到缓冲区有数据虽然我们可以采用IO多路复用来避免这个问题但是这也是一种消耗而且写起来实在不合直觉 如果能把线程细分为更多的子任务就好了我们可以主动控制多个子任务进行交替执行 假设read函数是一个单独的子任务当read函数发现缓冲区没有内容时则直接“阻塞”让出这个线程的执行权让线程去执行其他的任务 当可读条件满足时在去唤醒read的子任务从上次read“阻塞”的地方继续执行 这里的“阻塞”打了引号因为并非是真的阻塞而是相当于按下了暂停键整个线程仍然是没有阻塞的 这样线程的并发就进一步提高了这里的子任务也可以理解为是一个函数我们只需要把当前函数的栈空间和寄存器状态保留即可 什么时候使用协程 主要是IO密集型的任务需要例如网络请求爬虫文件读取web框架等等 对于计算密集型任务还是别用了因为本身就不需要大量的线程切换还增加了协程切换的开销 协程的类别 协程在不同的语言实现也不太一样PythonJavaGoC20都支持协程大致可以分为两大类 有栈协程stackful也就是类似于内核的线程协程拥有自己的栈空间不同协程的切换需要切换对应栈的上下文只是操作系统不会陷入内核态例如goroutinelibco无栈协程stackless这种就是把上下文会放到公共内存切换的时候使用状态机来切换而不用切换上下文比有栈协程要清凉C20RustJavaScript都是这种 这里的有栈和无栈指的是协程之间是否存在调用栈的关系 除此之外还有 对称协程允许协程之间互相调用可以直接切换到其他的协程而不必须返回到调用他的协程可以写你刚才协程环和协程网非对称协程也叫做一对多的协程每个协程的控制权只能返回给直接调用他的协程这种调用关系是单向的 C20的协程 C20的协程是属于无栈协程非对称协程对协程的实现的底层原理实际上是通过关键字展开模板来实现的 协程的使用 关键字 主要的关键字有三个 co_await暂停协程的执行等待某个任务的完成co_return返回结果co_yield生成一个中间结果暂停协程 当一个函数中出现了这三个关键字中的任意一个时这个函数就会被判定为协程了 我们来写一个简单的协程猜数字先大概看一下这是个什么东西 可以的话请跟着思路一起写而非直接复制完整代码来看这里还是比较复杂的 co_wait 框架 我们先搭一个基本的框架 #include coroutine #include iostream using namespace std;struct CoRet { };struct Input { };CoRet Guess() {Input input;int g co_await input;cout 协程你猜的是 g endl; }int main() {auto ret Guess(); cout 主函数猜一猜 endl;return 0; }这里我们定义了两个类分别是输入和输出和一个协程Guess怎么看这是一个协程能因为其中用来co_await 有些奇怪的点是Guess没有人恶化的返回语句但是他可以拥有返回类型这个返回类型就包含了这个协程的管理句柄还有其中的一些回调函数 这时候编译器提示我们他在CoRet这个返回值类型中找不到promise_type这个类 编译器需要我们提供promise_type这个类来对协程进行管理他会在Guess开始执行是自动初始化promise_type这个类 接下来我们添加上相应的代码 /// brief 协程函数的返回值类型 struct CoRet {/// brief 用于控制协程的运行协程内外数据的交换struct promise_type{}; }; /// 虽然这个函数没有任何的返回语句但是他仍然可以拥有返回类型 /// 这个返回类型就包含了这个协程的管理句柄还有一些回调函数 CoRet Guess() {// 在这里编译器会隐含的创建一个对象 当然这里是简化过后的// CoRet::promise_type promise;Input input;int g co_await input; cout 协程你猜的是 g endl; }然后这里编译器优惠提示我们 struct promise_type 里面少了一些函数我们一一介绍 suspend_never initial_suspend(){return {};}suspend_never final_suspend() noexcept{return {};}/// brief 异常处理void unhandled_exception(){}首先是这三个 前两个是当协程调用之前和调用结束之后是否需要暂停等待 如何区别呢就是用suspend_never和suspend_always这两个提供给我们的类这两个类是可以被直接co_await的对象 suspend_never 不暂停 继续运行 suspend_always 暂停等待 执行逻辑跳回到调用的地方 unhandled_exception当协程出现异常时的处理函数 还少了一个是 CoRet get_return_object(){return{coroutine_handlepromise_type::from_promise(*this)};}这个函数是用于获取 协程暂停时返回的对象的这个对象可以是任意一个对象 但是更加通用的对象其实是返回这个协程的管理句柄不然没有办法管理协程了就 这里用的就是coroutine_handlepromise_type类型作为句柄 需要注意的是这个句柄是需要作为返回值的成员变量的因此整个CoRet类就是长这样 /// brief 协程函数的返回值类型 struct CoRet {/// brief 用于控制协程的运行协程内外数据的交换struct promise_type{/// return 提供了两个可以被 co_await 的对象/// suspend_never 不暂停 继续运行/// suspend_always 暂停等待 执行逻辑跳回到调用的地方suspend_never initial_suspend(){return {};}suspend_never final_suspend() noexcept{return {};}/// brief 异常处理void unhandled_exception(){}/// note 这个函数是用于获取协程暂停时返回的对象/// 这里其实可以返回的是一个任意对象/// 但是没有办法通过协程的返回值来控制协程的进行/// 最一般的方式是这样的 利用 promise 对象返回一个控制协程运行的句柄CoRet get_return_object(){return{coroutine_handlepromise_type::from_promise(*this)};}};// 控制协程运行的句柄coroutine_handlepromise_type _h; }; 补全编译器给我们优化的协程就是这样的 /// brief /// return 协程函数的返回值类型 /// note /// 虽然这个函数没有任何的返回语句但是他仍然可以拥有返回类型 /// 这个返回类型就包含了这个协程的管理句柄还有一些回调函数 CoRet Guess() {// 在这里编译器会隐含的创建一个对象 当然这里是简化过后的// CoRet::promise_type promise;// 利用对象产生一个返回的对象每一次协程被暂停返回的就是这个对象// CoRet ret promise.get_return_object();// 用创建的对象 co_await initial_suspend 的结果// co_await promise.initial_suspend();Input input;int g co_await input; // 运行到这里时跳转出去cout 协程你猜的是 g endl;// co_await promise.final_suspend();}然后编译器又提示我们Input类也少东西了 分别是await_readyawait_suspendawait_resume这三个函数 第一个await_ready表示当遇到co_await 时 是否需要暂停当前协程并跳转回去 如果不需要暂停跳转则返回true 如果需要暂停等待则返回false bool await_ready(){return false;}第二个await_suspend是在协程即将要被暂停时可以执行的行为 是这样写的 void await_suspend(coroutine_handleCoRet::promise_type h){// h.promise(); 这里协程管理句柄的promise成员函数返回的对象的作用// 其实就是获取协程的管理对象} 参数是当前协程的管理句柄 在即将暂停之间我们可以得到管理句柄并且执行一些操作 这个函数的返回值指的是 在这个协程在暂停之后代码执行要跳转到的地方 如果是 void 则跳转到调用这个协程的地方 如果是 其他协程的句柄 则跳转到对应协程继续运行 类似于析构函数和构造函数 调用子类的构造函数时也必定会自动调用父类的构造函数 这里就是 在遇到暂停之后可以使用void返回到原来调用协程的地方也可以继续调用其他协程 不同之处就是这里需要显式写出来 第三个是await_resume 在 co_wait 需要一个返回值的时候 才需要写 这里的返回值类型是可以自己设定的可以代表不同的含义 int await_resume(){return 0;}一阶段完成 这时候编译器也不再提示什么报错信息了 完整代码是这样 #include coroutine #include iostream using namespace std;/// brief 协程函数的返回值类型 struct CoRet {/// brief 用于控制协程的运行协程内外数据的交换struct promise_type{/// return 提供了两个可以被 co_await 的对象/// suspend_never 不暂停 继续运行/// suspend_always 暂停等待 执行逻辑跳回到调用的地方suspend_never initial_suspend(){return {};}suspend_never final_suspend() noexcept{return {};}/// brief 异常处理void unhandled_exception(){}/// note 这个函数是用于获取协程暂停时返回的对象/// 这里其实可以返回的是一个任意对象/// 但是没有办法通过协程的返回值来控制协程的进行/// 最一般的方式是这样的 利用 promise 对象返回一个控制协程运行的句柄CoRet get_return_object(){return{coroutine_handlepromise_type::from_promise(*this)};}};// 控制协程运行的句柄// _h.resume() - 继续运行协程, _h() - 也是的coroutine_handlepromise_type _h; };struct Input {/// brief 当遇到 co_await 时 是否需要暂停当前协程并跳转回去/// return 不需要暂停跳转返回true | 需要暂停等待返回falsebool await_ready(){return false;}/// brief 定义在协程即将要被暂停时的一些行为/// param h 当前协程的管理句柄/// note 在即将暂停之间我们可以得到管理句柄并且执行一些操作/// return 这个函数的返回值指的是 在这个协程在暂停之后代码执行要跳转到的地方/// 如果是 void 则跳转到调用这个协程的地方/// 如果是 其他协程的句柄 则跳转到对应协程继续运行/// 类似于析构函数和构造函数 /// 调用子类的构造函数时也必定会自动调用父类的构造函数/// 这里就是 在遇到暂停之后可以使用void返回到原来调用协程的地方也可以继续调用其他协程/// 不同之处就是这里需要显式写出来void await_suspend(coroutine_handleCoRet::promise_type h){// h.promise(); 这里协程管理句柄的promise成员函数返回的对象的作用// 其实就是获取协程的管理对象}/// brief 在 co_wait 需要一个返回值的时候 才需要写/// return 这里的返回值类型是可以自己设定的可以代表不同的含义int await_resume(){return 0;} };/// brief /// return 协程函数的返回值类型 /// note /// 虽然这个函数没有任何的返回语句但是他仍然可以拥有返回类型 /// 这个返回类型就包含了这个协程的管理句柄还有一些回调函数 CoRet Guess() {// 在这里编译器会隐含的创建一个对象 当然这里是简化过后的// CoRet::promise_type promise;// 利用对象产生一个返回的对象每一次协程被暂停返回的就是这个对象// CoRet ret promise.get_return_object();// 用创建的对象 co_await initial_suspend 的结果// co_await promise.initial_suspend();Input input;int g co_await input; // 运行到这里时跳转出去// co_await 后面可以加的是一个对象 但是也需要加一点东西cout 协程你猜的是 g endl;// co_await promise.final_suspend();}int main() {auto ret Guess(); // 运行到 co_await 时跳转回来cout 主函数猜一猜 endl;ret._h.resume(); // 运行到这里时跳转回去return 0; }运行结果是这样的 我们可以画一下协程和主函数的调用关系 数据交换 这里我们可以发现在CoRet这对象里的promise对象就是沟通协程内外的桥梁 一个自然的想要给协程输入的方法其实就是给这个promise_type对象中新建一个成员变量然后在Input对象里面存一个promise_type新增的成员变量的地址 在调用await_suspend()时就使用promise对象中的地址对Input对象中的指针赋值然后再在await_resume()中返回即可 显然这种方法曲折又复杂没什么人喜欢的 这样我们创建一个新的类 来作为输入将这个类作为协程的成员变量 这个类在main中初始化然后通过参数传递给函数再用协程的Input接收这个参数并初始化协程就能够完成协程和main函数之间的参数传递了 struct Note {int num;Note() : num(100) {} }; struct Input {Note in;bool await_ready(){cout await_ready endl;return false;}void await_suspend(coroutine_handleCoRet::promise_type h){cout await_suspend endl;}int await_resume(){cout await_resume endl;return in.num;} }; CoRet Guess(Note note) {Input input{note};int g co_await input; cout 协程你猜的是 g endl; } int main() {Note note;auto ret Guess(note); cout 主函数猜一猜 endl;ret._h.resume();return 0; }co_yield 这个关键字其实就等价于 co_await promise.yield_value(expr) 这里我们再加一点东西 在Guess开始的时候产生一个1到114的随机数 int res (rand() % 114 1); 然后从协程外面读取一个数字 再调用co_yield对比较数字的大小 co_yield (res g ? 1 : (res g ? 0 : -1)); 这里三目运算符的结果无非就是-1 0 1这三种 就相当于调用了这样的函数 co_await promise.yield_value(-1\0\1); 但是我们并没有实现yield_value 因此需要写一下 他的输入其实就是co_yield后面的那个表达式 返回值则是用于区分执行完之后是否需要暂停等待 如果是suspend_never则不等待 如果是suspend_always则进行等待 为了保存这个co_yield输入的参数我们需要在promise对象中添加一个参数 suspend_always yield_value(int r){out r;return {};}int out;这样当协程比完大小之后就会把结果赋值到协程管理句柄的out中 然后在主函数中就可以直接取到结果了 int main() {srand(time(nullptr));Note note;auto ret Guess(note); // 运行到 co_await 时跳转回来cout 主函数猜一猜 endl;note.num 10;ret._h.resume(); // 运行到这里时跳转回去cout 主函数猜的结果是 ((ret._h.promise().out 1) ? 猜大了 : ((ret._h.promise().out 0) ? 猜对了 : 猜小了)) endl;return 0; }co_return 这个co_return其实和co_yield是差不多的 他也是会调用一个return_value的函数不同的是他会在管理句柄中标记这个协程是否已经完成 在协程管理句柄中有一个成员函数是done()可以获取协程是否执行完成的状态 在这个例子里面我们想要获取res同样就是在promise对象中添加一个参数 然后进行赋值就行 void return_value(int r){res r;}int res;在Guess的最后调用co_return res;就会自动转化为co_await return_value(res); 然后在main函数中就可以读取到了 完整代码 #include coroutine #include iostream using namespace std;/// brief 协程函数的返回值类型 struct CoRet {/// brief 用于控制协程的运行协程内外数据的交换struct promise_type{/// return 提供了两个可以被 co_await 的对象/// suspend_never 不暂停 继续运行/// suspend_always 暂停等待 执行逻辑跳回到调用的地方suspend_never initial_suspend(){cout initial_suspend endl;return {};}suspend_never final_suspend() noexcept{cout final_suspend endl;return {};}/// brief 异常处理void unhandled_exception(){}/// note 这个函数是用于获取协程暂停时返回的对象/// 这里其实可以返回的是一个任意对象/// 但是没有办法通过协程的返回值来控制协程的进行/// 最一般的方式是这样的 利用 promise 对象返回一个控制协程运行的句柄CoRet get_return_object(){cout get_return_object endl;return {coroutine_handlepromise_type::from_promise(*this)};}suspend_always yield_value(int r){out r;return {};}int out;void return_value(int r){res r;}int res;};// 控制协程运行的句柄// _h.resume() - 继续运行协程, _h() - 也是的coroutine_handlepromise_type _h; };struct Note {int num; };struct Input {Note in;/// brief 当遇到 co_await 时 是否需要暂停当前协程并跳转回去/// return 不需要暂停跳转返回true | 需要暂停等待返回falsebool await_ready(){cout await_ready endl;return false;}/// brief 定义在协程即将要被暂停时的一些行为/// param h 当前协程的管理句柄/// note 在即将暂停之间我们可以得到管理句柄并且执行一些操作/// return 这个函数的返回值指的是 在这个协程在暂停之后代码执行要跳转到的地方/// 如果是 void 则跳转到调用这个协程的地方/// 如果是 其他协程的句柄 则跳转到对应协程继续运行/// 类似于析构函数和构造函数/// 调用子类的构造函数时也必定会自动调用父类的构造函数/// 这里就是 在遇到暂停之后可以使用void返回到原来调用协程的地方也可以继续调用其他协程/// 不同之处就是这里需要显式写出来void await_suspend(coroutine_handleCoRet::promise_type h){cout await_suspend endl;// h.promise(); 这里协程管理句柄的promise成员函数返回的对象的作用// 其实就是获取协程的管理对象}/// brief 在 co_wait 需要一个返回值的时候 才需要写/// return 这里的返回值类型是可以自己设定的可以代表不同的含义int await_resume(){cout await_resume endl;return in.num;}};/// brief /// return 协程函数的返回值类型 /// note /// 虽然这个函数没有任何的返回语句但是他仍然可以拥有返回类型 /// 这个返回类型就包含了这个协程的管理句柄还有一些回调函数 CoRet Guess(Note note) {// 在这里编译器会隐含的创建一个对象 当然这里是简化过后的// CoRet::promise_type promise;// 利用对象产生一个返回的对象每一次协程被暂停返回的就是这个对象// CoRet ret promise.get_return_object();// 用创建的对象 co_await initial_suspend 的结果// co_await promise.initial_suspend();int res (rand() % 114) 1;Input input{note};int g co_await input; // 运行到这里时跳转出去// co_await 后面可以加的是一个对象 但是也需要加一点东西cout 协程你猜的是 g endl;co_yield (res g ? 1 : (res g ? 0 : -1));co_return res;// co_await promise.final_suspend(); }int main() {srand(time(nullptr));Note note;auto ret Guess(note); // 运行到 co_await 时跳转回来cout 主函数猜一猜 endl;note.num 10;ret._h.resume(); // 运行到这里时跳转回去cout 主函数猜的结果是 ((ret._h.promise().out 1) ? 猜大了 : ((ret._h.promise().out 0) ? 猜对了 : 猜小了)) endl;cout 主函数随机数是 ret._h.promise().res endl;return 0; }
- 上一篇: 营销方案 网站深圳市住房和城乡建设厅网站
- 下一篇: 营销技巧美剧巩义企业网站快速优化多少钱
相关文章
-
营销方案 网站深圳市住房和城乡建设厅网站
营销方案 网站深圳市住房和城乡建设厅网站
- 技术栈
- 2026年04月20日
-
营销导向的企业网站优化厦门seo小谢
营销导向的企业网站优化厦门seo小谢
- 技术栈
- 2026年04月20日
-
营销策划网站适合女生的计算机专业有哪些
营销策划网站适合女生的计算机专业有哪些
- 技术栈
- 2026年04月20日
-
营销技巧美剧巩义企业网站快速优化多少钱
营销技巧美剧巩义企业网站快速优化多少钱
- 技术栈
- 2026年04月20日
-
营销培训方案南阳网站排名优化
营销培训方案南阳网站排名优化
- 技术栈
- 2026年04月20日
-
营销式网站建设wordpress 死链提交
营销式网站建设wordpress 死链提交
- 技术栈
- 2026年04月20日






