libgo 源码剖析(1. libgo简介与调度浅谈)

闲谈

协程是一个很早的概念了,早些年的游戏行业中已经大规模地在使用,像lua、go这些语言中的协程原语已经相对比较完善了,一般来说直接使用就好,但是在系统后台开发上,出现的时间并不长。
我是做C++方向的后台开发,目前国内一些公司也开源了一些C++协程库,但目前来说,还是在逐步完善的阶段。最早接触的C++协程库是腾讯微信的 libco,可以说是相当轻量级的协程,网上关于libco的实现的文章也是相对较多,这里的话不会去过多地叙述。



在网上查找关于 libgo 的资料,关于代码实现的文章并没有多少,因此,打算自己看代码总结,之后的文章中,可能会针libgo和libco的部分功能进行简单对比,不足之处,希望读者指出。

背景

因为工作需要,以前系统的异步框架已经显得不再那么地具有扩展性,异步使得原本很简单的逻辑(读->处理->写),要拆分开来成多个阶段,通过回调来响应各个事件,因此有计划地使用协程来代替。

为什么最后选择了libgo,而没有选择更加轻量级的libco ?网上有人给出过两者的性能对比,从自旋锁、协程的数量以及栈空间、线程支持等各个角度考虑,貌似libgo完胜。

图片来源于网络

性能对比数据来源于网络,并不是说libco不好,也许各自应用的场景略有不同,libco几千行的代码可以实现一个相对较完备的协程,而且经得住微信后台庞大的数据流量,自有它的优势。由于对 libgo 的代码正在研究当中,因此,暂不对两者评价。

协程

不管是什么样的协程,最核心的内容,都是在系统发生阻塞的时候上层主动让出CPU,切换就绪协程的上下文,简要总结,有如下几个方面:

  1. 上下文切换的实现
  2. 系统函数的hook;
  3. 协程调度;
  4. 时间管理;

libgo 源码

https://github.com/yyzybb537/libgo

libgo 目录结构说明

[email protected]:~/code/libgo/libgo-master$ ll
total 64
[email protected]  1 muhui  staff  5913 11  7 11:20 CMakeLists.txt
[email protected]  1 muhui  staff  1084 11  7 11:20 LICENSE
[email protected]  1 muhui  staff  8758 11  7 11:20 README.md
[email protected]  1 muhui  staff  4230 11  7 11:20 TODO
[email protected]  4 muhui  staff   128 11  7 11:20 imgs
[email protected] 15 muhui  staff   480 11  7 11:20 libgo
[email protected]  8 muhui  staff   256 11  7 11:20 test
[email protected]  6 muhui  staff   192 11  7 11:20 third_party
[email protected] 20 muhui  staff   640 11  7 11:20 tutorial
[email protected]  4 muhui  staff   128 11  7 11:20 vs_proj
[email protected]:~/code/libgo/libgo-master$ cd libgo/
[email protected]:~/code/libgo/libgo-master/libgo$ ll
total 16
[email protected]  4 muhui  staff   128 11  7 11:20 cls
[email protected] 19 muhui  staff   608 11  7 11:20 common
[email protected]  6 muhui  staff   192 11  7 11:20 context
[email protected]  1 muhui  staff  1848 11  7 11:20 coroutine.h
[email protected]  5 muhui  staff   160 11  7 11:20 debug
[email protected]  4 muhui  staff   128 11  7 11:20 defer
[email protected]  1 muhui  staff    36 11  7 11:20 libgo.h
[email protected]  4 muhui  staff   128 11  7 11:20 netio
[email protected]  5 muhui  staff   160 11  7 11:20 pool
[email protected]  8 muhui  staff   256 11  7 11:20 scheduler
[email protected]  7 muhui  staff   224 11  7 11:20 sync
[email protected]  4 muhui  staff   128 11  7 11:20 task
[email protected]  4 muhui  staff   128 11  7 11:20 timer

libgo 做的较好的一点是增加了对windows 环境的支持等,我们只针对 Linux 环境做研究。

  • TODO:libgo 后续会逐步完善或增加的功能;
  • libgo:源码实现的主目录,关于协程和调度策略的实现都在该目录下;
  • test:测试代码;
  • tutorial:libgo 使用教程代码;
  • vs_proj:VS 环境下如何使用libgo。

    在libgo目录下

    • task:协程的相关实现;
    • scheduler:协程调度的实现;
    • debug:libgo 自带的调试功能(用于协程状态的定位等);
    • coroutine.h:对一些常用对方法进行了重定义。
  • netio:hook的系统调用;
  • context:上下文的切换;
  • pool:libgo 实现的连接池



libgo调度原理概述

我们知道,协程是用户态线程,因此libco的话是不支持线程的。但在libgo中,线程同样是支持的,这于它的调度方式有关。

首先我们要说的一点是,在libgo中,每个协程是一个task,libgo 的调度并不是直接作用于协程,是通过间接调度实现的。

libgo中有调度器(scheduler)和执行器(processer)的概念:

  1. 直接负责协程调度的是执行器,它会在协程阻塞的时候切出上下文,并切入一个就绪协程的上下文去继续处理,当没有可执行的协程时,执行器就会阻塞等待,当有新到来的任务时,会继续处理;
  2. 负责管理执行器的是调度器,对调度器而言,每个执行器是一个单独的线程,调度器做的最主要的工作,就是平衡各个执行器中的协程数量,防止饥饿效应,部分执行器过忙,部分执行器却没有task可执行,另外,如果某个执行器卡住,调度器也会将执行器中的可运行协程取出,放到负载最低的执行器上。
  3. 当然,调度器的个数的话是支持动态扩展的。

如下图:

关于代码实现会在下一篇中叙述。

原文地址:http://blog.51cto.com/muhuizz/2328117

时间: 2024-08-30 16:25:25

libgo 源码剖析(1. libgo简介与调度浅谈)的相关文章

libgo 源码剖析(2. libgo调度策略源码实现)

本文将从源码实现上对 libgo 的调度策略进行分析,主要涉及到上一篇文章中的三个结构体的定义: 调度器 Scheduler(简称 S) 执行器 Processer(简称 P) 协程 Task(简称 T) 三者的关系如下图所示: 本文会列出类内的主要成员和主要函数做以分析. 1. 协程调度器:class Scheduler libgo/scheduler/scheduler.h class Scheduler{ public: /* * 创建一个调度器,初始化 libgo * 创建主线程的执行器

libgo 源码剖析(3. libgo上下文切换实现)

在 libgo 的上下文切换上,并没有自己去实现创建和维护栈空间.保存和切换 CPU 寄存器执行状态信息等的任务,而是直接使用了 Boost.Context.Boost.Context 作为众多协程底层支持库,性能方面一直在被优化. Boost.Context所做的工作,就是在传统的线程环境中可以保存当前执行的抽象状态信息(栈空间.栈指针.CPU寄存器和状态寄存器.IP指令指针),然后暂停当前的执行状态,程序的执行流程跳转到其他位置继续执行,这个基础构建可以用于开辟用户态的线程,从而构建出更加高

【Java集合源码剖析】HashMap源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955 HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap. HashMap 实现了Serializable接口,因此它支持序列化,

转:【Java集合源码剖析】Vector源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/35793865   Vector简介 Vector也是基于数组实现的,是一个动态数组,其容量能自动增长. Vector是JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的(其实也只是相对安全,有些时候还是要加入同步语句来保证线程的安全),可以用于多线程环境. Vector没有丝线Serializable接口,因此它不支持序列化,实现了Cloneable接口,能被克隆,实

GDAL源码剖析(一)(转载)

GDAL源码剖析(一) GDAL 前言:一直在使用和研究GDAL的相关东西,发现网上对GDAL的内容倒是不少,但是很少有系统的介绍说明,以及内部的一些结构说明,基于这些原因,将本人的一些粗浅的理解放在此处,形成一个系列,暂时名为<GDAL源码剖析>(名称有点大言不惭,欢迎大家口水吐之,板砖拍之),供大家交流参考,有什么错误之处,望大家不吝指正,本系列对于GDAL的使用均是在Windows平台下,对于Linux平台下的不在此系列讨论范围之内.此外,转载本博客内容,请注明出处,强烈鄙视转载后不注明

【Java集合源码剖析】LinkedHashmap源码剖析

LinkedHashMap简介 LinkedHashMap是HashMap的子类,与HashMap有着同样的存储结构,但它加入了一个双向链表的头结点,将所有put到LinkedHashmap的节点一一串成了一个双向循环链表,因此它保留了节点插入的顺序,可以使节点的输出顺序与输入顺序相同. LinkedHashMap可以用来实现LRU算法(这会在下面的源码中进行分析). LinkedHashMap同样是非线程安全的,只在单线程环境下使用. LinkedHashMap源码剖析 LinkedHashM

PCL源码剖析之MarchingCubes算法

原文:http://blog.csdn.net/lming_08/article/details/19432877 MarchingCubes算法简介 MarchingCubes(移动立方体)算法是目前三围数据场等值面生成中最常用的方法.它实际上是一个分而治之的方法,把等值面的抽取分布于每个体素中进行.对于每个被处理的体素,以三角面片逼近其内部的等值面片.每个体素是一个小立方体,构造三角面片的处理过程对每个体素都“扫描”一遍,就好像一个处理器在这些体素上移动一样,由此得名移动立方体算法. MC算

【Java集合源码剖析】ArrayList源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/35568011 ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的C

转:【Java集合源码剖析】HashMap源码剖析

转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955   您好,我正在参加CSDN博文大赛,如果您喜欢我的文章,希望您能帮我投一票,谢谢! 投票地址:http://vote.blog.csdn.net/Article/Details?articleid=35568011 HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动