首页
学习
活动
专区
圈层
工具
发布

有栈协程和无栈协程

当前很多的编程语言都内置协程特性或者有自己的协程库,如C/C++的libco、golang的goroutine等。而在实现机制上,又可以划分为有栈协程和无栈协程,我们分别进行介绍。...有栈协程 所谓有栈协程是指执行环境的恢复是通过函数栈(即运行时上下文)的恢复实现的,在此之前我们先回忆一下函数调用的基础知识。...,函数通过函数返回语句实现执行权限的归还&通过栈中返回地址实现被中断执行流程的恢复,而有栈协程正是基于这一朴素的想法实现的:在有栈协程中,将每个并行事务看成是一个函数调用,而协程库负责把让出执行权时的协程的上下文缓存起来...,然后把执行权限通过接口co_swap交还给父协程即可,并将当前协程退栈 无栈协程 有栈协程是基于函数切换上下文恢复的思路实现被中断协程的继续执行,但是这个上下文里面有返回地址,即下一条指令的地址...这样既解决了上下文切换很多不必要的操作,也解决了程序修改后指令地址改变导致的无法恢复的问题 无栈协程的Demo实现 一个协程库要解决以下几个问题: 1)如何在协程阻塞调用时归还执行权限?

6.4K43

协程-无栈协程(下)

无栈协程库——protothread ProtoThread源码如下所示: #define LC_INIT(s) s = 0; #define LC_RESUME(s) switch(s) { case...,直接通过return交出执行权限;在交出执行权限之前,调用LC_SET,查看LC_SET的代码,看到这里我们看PT是通过记录行号给源码打标签 ·ProtoThread通过宏PT_SCHEDULE来实现协程的调度...,而外层用name->RoleData的映射关系管理协程及其他协程中间态数据;     需要注意的是——以protothread来说: ·对于无栈协程来说,因为不存在指针等信息,所以无栈协程的所有信息是可以缓存在共享内存的...,以避免因为逻辑修改导致协程不可恢复的场景);     对于无栈协程来说,执行流的恢复只是通过找到下一条指令的执行地址,但是不包括上下文,这意味着无栈协程里面不能有局部变量,需要我们手动把后面需要用到的局部变量缓存起来...此外这里无栈协程是通过switch-case实现的,嵌套的switch-case会产生问题,限制比较多,所以也不适用于线上场景。

1.1K20
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    初识协程栈

    由于Go协程的栈是Go运行时管理的,并分配于堆上,不由操作系统管理,所以我们先来看看协程栈的内存如何被Go运行时管理和回收的。本篇文章先从初步认识协程栈开始。...查看本系列完整内容请访问 https://tigerb.cn/go/#/kernal/ 前言 ---- 为了对协程栈有个初步的认识,我们先来回顾数据结构中栈的概念,再来看看内存栈的概念作用,最后我们再来通过对比进程中的栈内存和线程中的栈内存来对协程中的栈内存有个初步的认知...谁决定了代码在运行过程中,从栈空间分配或释放多少内存? 我们分别从「进程栈」和「线程栈」、「协程栈」视角看看以上两个问题。 进程栈 什么是进程栈?...谁决定了代码在运行过程中,从栈空间(线程栈)分配或释放多少内存? 答:同进程,编译器决定。 协程栈 什么是协程栈?...答:使用`go`关键字创建一个协程时,Go运行时从堆上分配一块连续内存作为协程的栈空间。 谁决定了协程栈的栈空间的大小范围?

    29630

    无栈协程(上)

    无栈协程 有栈协程是基于函数切换上下文恢复的思路实现被中断协程的继续执行,但是这个上下文里面有返回地址,即下一条指令的地址,所以当程序发生改动重新编译生成,指令地址有可能发生改变,这种对于需要重新编译生成发布的发布场景支持并不友好...无栈协程的Demo实现     一个协程库要解决以下几个问题:     1)如何在协程阻塞调用时归还执行权限?     2)如何选择合适的协程进行调度?     ...在前面讨论中,可以认为协程是一个函数的调用,那么协程的恢复无非是从调用中断处继续执行,而对于无栈协程不需要进行上下文恢复,则核心是通过存储标签保证下次调度能从预期的地方继续执行,那么就有:     1)...,这个协程库提供相应接口支持即可;     3)针对问题三,因为协程被认为是一次函数调用,则执行权限交给对应被调度协程本质上调用协程的接口即可,即通过接口调用实现执行权限的传递;     4)如何实现中断指令流的继续...虽然我们可以对上述进行优化和封装,但是在这我们并不准备过多赘述,后面我们则直接看一个开源的无栈协程库-protothread     未完待续...

    82840

    小白学协程笔记3-实现自己的协程库(独立栈,共享栈)-2021-2-22

    文章目录 前言 一、协程库实现-独立栈 1.协程结构体定义 2.协程调度器定义 3.协程创建函数 4.协程启动/恢复函数 5.协程挂起函数 6.判断协程是否运行完毕函数 7.使用示例 二、协程库实现-...,本文将介绍如何通过c语言实现自己的协程库,分为独立栈和共享栈两种实现,代码见git仓库。...一、协程库实现-独立栈 通过独立栈实现的协程库中的每一个协程都有自己独立的栈空间,协程栈大小固定且互不干扰。...-共享栈 通过共享栈实现的协程库中的每一个协程在运行时都使用一个公共的栈空间,当协程挂起时将自己的数据从共享栈拷贝到自己的独立栈,协程运行时又将数据从独立栈拷贝到共享栈运行,本文是参考cloudyun大神代码进行简要分析...而共享栈实现时协程运行时,数据存放在schedule_t结构体中的stack成员中,这个栈被所有协程共享。

    1.6K40

    协程实现原理

    今天我们来探讨一个问题,Go 协程的实现原理。此“协程”非彼”携程“。 线程实现模型 讲协程之前,我们先看下线程的模型。...我们知道在Linux操作系统编程中,往往都是通过fork()函数创建一个子进程来代表一个内核中的线程。一个进程调用fork()函数后,系统会先给新的进程分配资源,例如,存储数据和代码的空间。...JDK 1.8 Thread.java 中 Thread start 方法的实现,实际上是通过Native调用start0方法实现的;在Linux下, JVM Thread的实现是基于pthread_create...协程的实现原理 协程不只在Go语言中实现了,其实目前大部分语言都实现了自己的一套协程,包括C#、erlang、python、lua、javascript、ruby等。...协程正常结束后的状态为Done。 Fiber对象与Java的线程栈类似,主要用来维护Task的执行堆栈,Fiber是实现N:M线程映射的关键。

    69720

    我对无栈协程的理解

    从后台工程师的角度说,有栈协程的应用更普遍。例如,云风封装的非常经典的基于C的ucontext.h来实现的共享栈的协程,具体请见《C 的 coroutine 库》。...而golang在语言级实现的协程是独立栈的协程。...独立栈的协程实现相比共享栈的方式而言少了在每次切换上下文时候的栈数据拷贝,理论上来说性能更高一些,但是也有这样的问题: 共享栈的栈内存拷贝,也只是拷贝调用方开始的上下文切换的部分,这个数据也不算很大;...独立栈必然要为每个协程分配栈空间的内存,golang 1.4开始协程栈的大小是2kb,2kb可能对某些协程很浪费,对某些协程又完全不够;协程太多必然也导致分配和GC方面的压力。...以上只是用C代码来模拟无栈协程的运行模式而已,实际上自带generator(生成器)能力的编程语言会用一些语法糖来屏蔽复杂的切换细节,可以参考python+gevent的实现。

    1.4K30

    解密Go协程的栈内存管理

    网管碎碎念:堆和栈都是编程语言里的虚拟概念,并不是说在物理内存上有堆和栈之分,两者的主要区别是栈是每个线程或者协程独立拥有的,从栈上分配内存时不需要加锁。...; v1.4 — 将最小栈内存降低到了 2KB; 分段栈和连续栈 分段栈 Go 1.3 版本前使用的栈结构是分段栈,随着goroutine 调用的函数层级的深入或者局部变量需要的越来越多时,运行时会调用...连续栈 连续栈可以解决分段栈中存在的两个问题,其核心原理就是每当程序的栈空间不足时,初始化一片比旧栈大两倍的新栈并将原栈中的所有值都迁移到新的栈中,新的局部变量或者函数调用就有了充足的内存空间。...copystack会把旧栈里的所有内容拷贝到新栈里然后调整所有指向旧栈的变量的指针指向到新栈, 我们可以用下面这个程序验证下,栈扩容后同一个变量的内存地址会发生变化。...| FixedStack | NumStackOrders // -----------------+------------+--------------- // linux

    4.6K20

    队列实现栈&栈实现队列

    前言 给你两个栈你如何实现一个队列,给你两个队列你如何实现一个栈。 本文就跟大家分享下这两个问题的解决思路与实现过程,欢迎各位感兴趣的开发者阅读本文。...,我们先来看下如何用栈来实现队列: 我们的已知条件只有两个栈,将这两个栈进行标识:栈1、栈2 执行入队操作时,我们元素放进栈1。...接下来,我们来看下如何用队列来实现栈: 同样的,我们的已知条件有两个队列,将这两个队列进行标识:队列1,队列2 执行入栈操作时,将元素放进队列1 执行出栈操作时: 如果队列2为空,我们将队列1中除队首外的元素放进队列...实现代码 经过上述分析,我们有了实现思路,接下来我们就将上述思路转化为具体的代码,下述代码中将引入我们之前写好的队列与栈的实现代码,对此不了解的开发者请移步我的另外两篇文章:数组实现栈与对象实现栈、队列与双端队列的实现...栈实现队列 创建StacksAndQueues类文件,声明解决本文问题所需要的变量 // 栈与队列的相关操作 import Stack from "../..

    86120

    栈与栈的实现栈栈的基本操作栈的实现

    将数据压入栈 清空栈 栈的实现 软件实现——GO语言 软件的栈可以使用链表基本结构实现或使用数组实现:使用链表栈的优势是栈的容量几乎不限,确定是入栈出栈都需要开销较大的声明结构体;数组实现的优势是速度快...(自增自减一般有指令实现),但是空间必须预先指定。...,不同的是读取后不改变“栈顶指针”的位置 清空栈 func (a *Array_stack) Clear() { a.length = 0 } 直接将“栈顶指针”清零即可实现清空栈 切片栈 切片是一种...Go语言特有的数据结构,类似于动态数组,使用切片可以实现深度可变的栈。...stack_point[DEPTH_LOG - 1:0]; ram_write_data <= stack_write_data; end end endmodule Verilog实现栈的关键点有三个

    1.1K50

    从无栈协程到 C++异步框架

    而有栈协程和无栈协程的实现, 差异最大的地方就是如下两点了: 怎么保存和恢复当前的执行位置 怎么保存和恢复当前协程引用到的内存(变量等) 本篇主要侧重无栈协程, 无栈协程相关的机制后续会具体展开....libco, 与 boost.context 这样的高性能有栈协程实现机制后, 标准委员会还会继续寻求无栈协程的解决方案, 并最终将其作为 C++协程的实现机制呢, 这里分析主要的原因是为了解决有栈协程天然存在的限制...C++17 中基于 Duff Device Hack 的无栈协程实现, 以及 C++20 中的无栈协程做更深入的介绍. 2....但当时的 GCC 用的是 8.3 版本, 并不支持 coroutine20, 所以我们最终采用的是一个基于 C++17 的无栈协程实现方案, 也就是使用前面介绍的 Duff Device Hack 方式实现的无栈协程...Hack 的无栈协程实现的方式.

    2.9K41

    协程和Java实现

    Lua语言 Lua从5.0版本开始使用协程,通过扩展库coroutine来实现。 Python语言 正如刚才所写的代码示例,python可以通过 yield/send 的方式实现协程。...Go语言 Go语言对协程的实现非常强大而简洁,可以轻松创建成百上千个协程并发执行。...java协程框架----kilim实现机制解析 java语言处理多任务的模式是基于多线程,java语言级别原生并不支持协程,我们想要java语言支持协程,就需要在线程和协程之间架起一道桥梁。...协程的核心在于调度那块由他来负责解决,遇到阻塞操作,立刻放弃掉,并且记录当前栈上的数据,阻塞完后立刻再找一个线程恢复栈并把阻塞的结果放到这个线程上去跑,这样看上去好像跟写同步代码没有任何差别,这整个流程可以称为...java协程的实现 早期,在JVM上实现协程一般会使用kilim,不过这个工具已经很久不更新了,现在常用的工具是Quasar,而本文章会全部基于Quasar来介绍。

    2.3K41

    【Kotlin 协程】协程底层实现 ② ( 协程调度器 | 协程任务泄漏 | 结构化并发 )

    文章目录 一、协程调度器 二、协程任务泄漏 三、结构化并发 一、协程调度器 ---- 协程 是在 调度器 中运行的 , 在协程中有 3 种调度器 : Dispatchers.Main 调度器 : 在 主线程...---- 协程任务泄漏 : 发起 协程任务 后 , 无法追踪任务的执行结果 , 任务等于无效任务 , 但是仍然会消耗 内存 , CPU , 网络 , 磁盘 等资源 ; Kotlin 中引入了 结构化并发机制...避免 协程任务泄漏 的情况发生 ; 协程任务泄漏 与 内存泄漏 类似 ; 三、结构化并发 ---- 结构化并发 使用场景 : 协程任务取消 : 在不需要协程任务的时候 , 取消协程任务 ; 追踪协程任务...: 追踪正在执行的协程任务 ; 发出错误信号 : 如果 协程任务执行失败 , 发出错误信号 , 表明执行任务出错 ; 协程任务 运行时 , 必须指定其 CoroutineScope 协程作用域 , 其会追踪所有的...协程任务 , CoroutineScope 协程作用域 可以取消 所有由其启动的协程任务 ; 常见的 CoroutineScope 协程作用域 : GlobalScope : 该作用域是 进程级别的

    1K20

    go 协程的实现笔记

    原文在此:Golang源码探索(二) 协程的实现原理 有时候G需要调用一些无法避免阻塞的原生代码, 这时M会释放持有的P并进入阻塞状态, 其他M会取得这个P并继续运行队列中的G...., 如果有待运行的G则重新进入自旋状态 G从无缓冲的channel获取不到数据, G会保存状态并变为等待中(_Gwaiting)并添加到channel的队列 go的调用规范非常的简单, 所有参数都通过栈传递..., 返回值也通过栈传递 参数和返回值都从低位到高位排列, go函数可以有多个返回值的原因也在于此....因为返回值都通过栈传递了 TLS的全称是Thread-local storage, 代表每个线程的中的本地数据. 当函数发现栈空间不足时, 会申请一块新的栈空间并把原来的栈内容复制过去....通过设置stackguard可以实现抢占,因为会触发栈扩张,栈扩张的时候检查是否等于一个特殊的常量,如果是,协程自身判断是否要抢占。 被枪占的g会到全局队列g中。

    68820
    领券