关于tars:TarsCpp-协程实现分析
作者:vivo 互联网服务器团队- Ye Feng本文介绍了协程的概念,并探讨了 Tars Cpp 协程的实现原理和源码剖析。 一、前言Tars 是 Linux 基金会的开源我的项目(https://github.com/TarsCloud),它是基于名字服务应用 Tars 协定的高性能 RPC 开发框架,配套一体化的经营治理平台,并通过伸缩调度,实现运维半托管服务。Tars 集可扩大协定编解码、高性能 RPC 通信框架、名字路由与发现、公布监控、日志统计、配置管理等于一体,通过它能够疾速用微服务的形式构建本人的稳固牢靠的分布式应用,并实现残缺无效的服务治理。 Tars 目前反对 C++,Java,PHP,Nodejs,Go 语言,其中 TarsCpp 3.x 全面启用对协程的反对,服务框架全面交融协程。本文基于TarsCpp-v3.0.0版本,探讨了协程在TarsCpp服务框架的实现。 二、协程的介绍2.1 什么是协程协程的概念最早呈现在Melvin Conway在1963年的论文("Design of a separable transition-diagram compiler"),协程认为是“能够暂停和复原执行”的函数。 协程能够看成一种非凡的函数,相比于函数,协程最大的特点就是反对挂起(yield)和复原(resume)的能力。如上图所示:函数不能被动中断执行流;而协程反对被动挂起,中断执行流,并在肯定机会复原执行。 协程的作用: 升高并发编码的复杂度,尤其是异步编程(callback hell)。协程在用户态中实现调度,防止了陷入内核,上下文切换开销小。2.2 过程、线程和协程咱们能够简略的认为协程是用户态的线程。协程和线程次要异同: 相同点:都能够实现上下文切换(保留和复原执行流)不同点:线程的上下文切换在内核实现,切换的机会由内核调度器管制。协程的上下文切换在用户态实现,切换的机会由调用方本身管制。过程、线程和协程的比拟: 2.3 协程的分类按管制传递(Control-transfer)机制分为:对称(Symmetric)协程和非对称(Asymmetric)协程。 对称协程:协程之间互相独立,调度权(CPU)能够在任意协程之间转移。协程只有一种管制传递操作(yield)。对称协程个别须要调度器反对,通过调度算法抉择下一个指标协程。非对称协程:协程之间存在调用关系,协程让出的调度权只能返回给调用者。协程有两种管制操作:复原(resume)和挂起(yield)。下图演示了对称协程的调度权转移流程,协程只有一个操作yield,示意让出CPU,返回给调度器。 下图演示了非对称协程的调度权转移流程。协程能够有两个操作,即resume和yield。resume示意转移CPU给被调用者,yield示意被调用者返回CPU给调用者。 依据协程是否有独立的栈空间,协程分为有栈协程(stackful)和无栈协程(stackless)两种。 有栈协程:每个协程有独立的栈空间,保留独立的上下文(执行栈、寄存器等),协程的唤醒和挂起就是拷贝和切换上下文。长处:协程调度能够嵌套,在内存中的任意地位、任意时刻进行。局限:协程数目增大,内存开销增大。无栈协程:单个线程内所有协程都共享同一个栈空间(共享栈),协程的切换就是简略的函数调用和返回,无栈协程通常是基于状态机或闭包来实现。长处:减小内存开销。局限:协程调度产生的局部变量都在共享栈上, 一旦新的协程运行后共享栈中的数据就会被笼罩, 先前协程的局部变量也就不再无效, 进而无奈实现参数传递、嵌套调用等高级协程交互。Golang 中的 goroutine、Lua 中的协程都是有栈协程;ES6的 await/async、Python 的 Generator、C++20 中的 cooroutine 都是无栈协程。 三、Tars 协程实现实现协程的外围有两点: 实现用户态的上下文切换。实现协程的调度。Tars 协程的由上面几个类实现: TC_CoroutineInfo 协程信息类:实现协程的上下文切换。每个协程对应一个 TC_CoroutineInfo 对象,上下文切换基于boost.context实现。TC_CoroutineScheduler 协程调度器类:实现了协程的治理和调度。TC_Coroutine 协程类:继承于线程类(TC_Thread),不便业务疾速应用协程。Tars 协程有几个特点: ...