协程 及 Libco 介绍

libco example_cond.cpp分析 腾讯libco库的example分析 可以参考https://github.com/zhoudayang/libco example_cond.cpp /* 生产者消费者模型 */ #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <queue> #inc... 阅读详情

libco 是腾讯开源的一个协程库,主要应用于微信后台RPC框架,下面我们从为什么使用协程、如何实现协程、libco使用等方面了解协程和libco。

 

why协程

为什么使用协程,我们先从server框架的实现说起,对于client-server的架构,server最简单的实现:

while(1) {accept();recv();do();send();}

串行地接收连接、读取请求、处理、应答,该实现弊端显而易见,server同一时间只能为一个客户端服务。

 

为充分利用好多核cpu进行任务处理,我们有了多进程/多线程的server框架,这也是server最常用的实现方式:

accept进程 - n个epoll进程 - n个worker进程

  1. accpet进程处理到来的连接,并将fd交给各个epoll进程
  2. epoll进程对各fd设置监控事件,当事件触发时通过共享内存等方式,将请求传给各个worker进程
  3. worker进程负责具体的业务逻辑处理并回包应答

以上框架以事件监听、进程池的方式,解决了多任务处理问题,但我们还可以对其作进一步的优化。

 

进程/线程是Linux内核最小的调度单位,一个进程在进行io操作时 (常见于分布式系统中RPC远程调用),其所在的cpu也处于iowait状态。直到后端svr返回,或者该进程的时间片用完、进程被切换到就绪态。是否可以把原本用于iowait的cpu时间片利用起来,发生io操作时让cpu处理新的请求,以提高单核cpu的使用率?

 

协程在用户态下完成切换,由程序员完成调度,结合对socket类/io操作类函数挂钩子、添加事件监听,为以上问题提供了解决方法。

 

用户态下上下文切换

Linux提供了接口用于用户态下保存进程上下文信息,这也是实现协程的基础:

  • getcontext(ucontext_t *ucp): 获取当前进程/线程上下文信息,存储到ucp中
  • makecontext(ucontext_t *ucp, void (*func)(), int argc, …): 将func关联到上下文ucp
  • setcontext(const ucontext_t *ucp): 将上下文设置为ucp
  • swapcontext(ucontext_t *oucp, ucontext_t *ucp): 进行上下文切换,将当前上下文保存到oucp中,切换到ucp

以上函数与保存上下文的 ucontext_t 结构都在 ucontext.h 中定义,ucontext_t 结构中,我们主要关心两个字段:

  • struct ucontext *uc_link: 协程后继上下文
  • stack_t uc_stack: 保存协程数据的栈空间

stack_t 结构用于保存协程数据,该空间需要事先分配,我们主要关注该结构中的以下两个字段:

  • void __user *ss_sp: 栈头指针
  • size_t ss_size: 栈大小

获取进程上下文并切换的方法,总结有以下几步:

  1. 调用 getcontext(),获取当前上下文
  2. 预分配栈空间,设置 xxx.uc_stack.ss_sp 和 xxx.uc_stack.ss_size 的值
  3. 设置后继上下文环境,即设置 xxx.uc_link 的值
  4. 调用 makecontext(),变更上下文环境
  5. 调用 swapcontext(),完成跳转

 

Socket族函数/io异步处理

当进程使用socket族函数 (connect/send/recv等)、io函数 (read/write等),我们使用协程切换任务前,需对相应的fd设置监听事件,以便io完成后原有逻辑继续执行。

 

对io函数,我们可以事先设置钩子,在真正调用接口前,对相应fd设置事件监听。同样,Linux为我们设置钩子提供了接口,以read()函数为例:

  1. 编写名字为 read() 的函数,该函数先对fd调用epoll函数设置事件监听
  2. read() 中使用dlsym(),调用真正的 read()
  3. 将编写好的文件打包,编译成库文件:gcc -shared -Idl -fPIC prog2.c -o libprog2.so
  4. 执行程序时引用以上库文件:LD_PRELOAD=/home/qspace/lib/libprog2.so ./prog

当在prog程序中调用 read() 时,使用的就是我们实现的 read() 函数。

对于glibc函数设置钩子的方法,可参考:Let’s Hook a Librarg Function

 

libco

有了以上准备工作,我们可以构建这样的server框架:

accept进程 - epoll进程(n个epoll协程) - n个worker进程(每个worker进程n个worker协程) 

该框架下,接收请求、业务逻辑处理、应答都可以看做单独的任务,相应的epoll、worker协程事先分配,服务流程如下:

  1. mainloop主循环,负责 i/监听请求事件,有请求则拉起一个worker协程处理;ii/如果timeout时间内没有请求,则处理就绪协程(即io操作已返回) 
  2. worker协程,如果遇到io操作则挂起,对fd加监听事件,让出cpu

libco 提供了以下接口:

  • co_create: 创建协程,可在程序启动时创建各任务协程
  • co_yield: 协程主动让出cpu,调io操作函数后调用
  • co_resume: io操作完成后(触发相应监听事件)调用,使协程继续往下执行

socket族函数(socket/connect/sendto/recv/recvfrom等)、io函数(read/write) 在libco的co_hook_sys_call.cpp中已经重写,以read为例:

复制代码
ssize_t read( int fd, void *buf, size_t nbyte )

{
    struct pollfd pf = { 0 };
    pf.fd = fd;
    pf.events = ( POLLIN | POLLERR | POLLHUP ); 

    int pollret = poll( &pf,1,timeout );  /*对相应fd设置监听事件*/
    ssize_t readret = g_sys_read_func( fd,(char*)buf ,nbyte );   /*真正调用read()*/
    return readret;
}
复制代码

 

小结

由最简单的单任务处理,到多进程/多线程(并行),再到协程(异步),server在不断地往极致方向优化,以更好地利用硬件性能的提升(多核cpu的出现、单核cpu性能不断提升)。

对程序员而言,可时常检视自己的程序,是否做好并行与异步,在硬件性能提升时,程序服务能力可不可以有相应比例的提升。

libco:libco是一个用C89编写的协作式多线程库 力宝 libco是一个用C89编写的协作式多线程库。 尽管协作式多线程仅限于单个CPU内核,但其扩展性比抢先式多线程好得多。 对于每秒需要100,000或更多上下文切换的应用程序,抢占式多线程处理所涉及的内核开销最终可能成为应用程序的瓶颈。 libco可以轻松扩展到每秒10,000,000或更多的上下文切换。 理想的用例包括服务器(HTTP,RDBMS)和仿真器(CPU内核等)。 目前,它包含以下后端: x86 CPU amd64 CPU PowerPC CPU PowerPC64 ELFv1 CPU PowerPC64 ELFv2 CPU ARM 32位CPU ARM 64位(AArch64)CPU POSIX平台(setjmp) Windows平台(光纤) 有关详细信息,请参见[doc / targets.md]。 有关文档,请参见[doc / usage 立即下载

相关推荐

C++ 开源协程库 libco——原理及应用1

(1) 有一段程序供其执行,这个是显然是必须的 (2) 有起码的“私有财产”,即线程专属的系统堆栈空间 (3) 有“户口”,操作系统教科书里叫做“进(线)程控制

协程 及 libco 介绍

libco是腾讯开源的一个协程库,主要应用于微信后台RPC框架,下面我们从为什么使用协程、如何实现协程、libco使用等方面了解协程和libco。 why协程 为什么使用协程,我们先从server框架的实现说起,对于client-server的架构,server最简单的实现: while(1) {accept();recv();do();send();} 串行地接收连接、读取请求、...

weixin_30753873的博客 302

QTabWidget动态标签页管理:从代码创建到UI设计的实战指南

本文深入探讨了QTabWidget动态标签页管理的实战技巧,涵盖从纯代码创建到UI设计器布局的两种核心方法。详细讲解了如何动态添加、插入、关闭标签页,并管理其内容与生命周期。文章还提供了标签页精细化控制、界面优化(如设置图标、样式表)以及构建简易多文档编辑器的进阶实战案例,帮助开发者灵活应对数据监控、多文档编辑等复杂界面需求。

omega的博客 867

arm64入栈出栈_使用 ARM64 汇编实现共享栈式协程

# 简述大约在半年以前,我曾经了解过协程的相关实现,也看过腾讯后台开源的协程库`libco`,对其中实现协程相关的汇编有很深的印象(`libco`适配的是 x86 平台)。接受了这样的思想,我在自己的毕业设计中,写出一套单片机汇编实现的协程。也自此之后,就有种念头在 iOS 端实现相关的代码。手机端使用的 CPU 跟单片机相差甚远,虽然我用的单片机也是 ARM 平台的,但和手机端 CPU 相比两者...

weixin_39639686的博客 849

Harness设计——Anthropic实战:规划器、生成器、评估器三角色协作详解

本文探讨了如何通过多智能体架构突破AI编码的瓶颈问题。文章首先分析了当前AI编码面临的两大核心挑战:上下文窗口限制导致的连贯性丧失,以及自我评估机制缺失引发的质量判断偏差。针对这些问题,作者提出了基于生成对抗网络(GAN)灵感的解决方案,设计了三智能体系统:规划器负责需求分析,生成器执行编码任务,评估器进行质量审查。 实验表明,在前端设计任务中,通过制定可量化的评分标准(设计质量、原创性、工艺、功能性)并建立生成-评估反馈循环,能显著提升输出质量。这种架构随后被扩展到全栈开发领域,采用类似敏捷开发的&quo

oe1019的专栏 868

命令行驱动视频剪辑:cutcli与AI自动化工作流实战

在视频内容创作领域,自动化与批量化处理是提升生产效率的关键。传统图形界面工具在应对重复性任务时往往效率低下,而通过命令行接口(CLI)驱动视频生成,则能实现流程的程序化控制。其技术原理在于将视频结构抽象为可编程的指令序列,通过解析命令生成标准化的工程文件。这种模式的核心价值在于将视频制作从手动操作转变为代码驱动,特别适合与AI编程助手集成,实现自然语言到视频草稿的自动转换。应用场景广泛覆盖社交媒体内容批量生产、教育视频自动化生成、数据可视化视频组装等领域。本文以cutcli工具为例,深入解析如何通过命令行与

weixin_42520239的博客 578

libco example_thread.cpp分析

程序 /*demo ./example_thread 1 */ #include "co_routine.h" #include "co_routine_inner.h" #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <pthread.h> #inc...

qq_38391187的博客 323

论文阅读—Square Attack: a query-efficient black-box adversarial attack via random search

论文阅读—Square Attack: a query-efficient black-box adversarial attack via random search 发表位置 ECCV 2020 摘要 作者提出了一种基于得分的黑盒Square attack,该模型不依赖于模型的局部梯度信息,因此可以绕过梯度隐藏防御攻击。Square Attack是一种随机搜索方法,它在随机位置选择局部的方形更新,使得每次迭代时扰动近似位于可行集的边界。 背景 当涉及到对安全至关重要的机器学习应用时,对抗性的例子尤其值得

yayayamaomaoya的博客 2494

coctx_swap.S、coctx.h、coctx.cpp上下文切换(汇编)—— libco源码分析、学习笔记

博客一级目录 二级目录——libco源码分析/学习笔记 参考大牛博客:传送门 coctx_swap.S大概功能 分析文件:coctx_swap.S、coctx.h、coctx.cpp 协程的调度和线程是很类似的。也需要保存和恢复上下文,这就要牵扯到各种寄存器了,而牵扯到寄存器,就不得不使用汇编指令。coctx_swap.S文件内实现的功能是协程之间上下文保存和切换。 贴一遍代码: ...

GreyBtfly的博客 1868

【华为OD机试真题】282、求满足条件的最长子串的长度 | 机试真题+思路参考+代码分析 (C++、Java、Py、C语言、JS)

题目描述 >给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度,字符串本身是其最长的子串,子串要求: >  1、只包含1个字母(a~ z,A~Z), 其余必须是数字; 2、字母可以在子 串中的任意位置; >  如果找不到满足要求的子串,如全是字母或全是数字,则返回-1

KJ.JK 1万+

OpenHarmony深度定制:从系统到模块的全景剖析与自定义模块实战

目标:在中新增一个算法库,让产品可直接调用。关闭不用的 20+ 系统部件,ROM 缩小 50 %;为自家芯片新增专用驱动模块,快速点亮开发板;内将核心算法库以部件形式集成,实现商业闭源。万物互联时代,差异化才是护城河。

m0_67505153的博客 1036

协程 及 libco介绍

libco 是腾讯开源的一个协程库,主要应用于微信后台RPC框架,下面我们从为什么使用协程、如何实现协程、libco使用等方面了解协程和libco。   why协程 为什么使用协程,我们先从server框架的实现说起,对于client-server的架构,se...

cool grass's blog 939

ESP8266开发之旅 基础篇① 走进ESP8266的世界

    欢迎大家来到ESP8266的世界,从现在开始,笔者将带领大家慢慢揭开ESP8266神秘的面纱。 1. 简介     从笔者的角度来说,ESP8266这个词可以理解为ESP8266EX芯片(当然,后面也有可能出现了其他芯片,这里首推ESP8266EX)以及依赖ESP8266EX芯片开发的系列模组的简称。     ESP8266EX是由乐鑫信息科技公司(Espressif)出品的一款应用于物联...

单片机菜鸟哥的博客 15万+

协程及libco介绍

转自:http://www.tuicool.com/articles/NJNrAn libco 是腾讯开源的一个协程库,主要应用于微信后台RPC框架,下面我们从为什么使用协程、如何实现协程、libco使用等方面了解协程和libco。 why协程 为什么使用协程,我们先从server框架的实现说起,对于client-server的架构,server最简单的实现: whil

Adam040606的博客 765

社区版 ABAP MCP 能不能读取 SAP S/4HANA 公有云开发对象,我的判断是能试,但不能当成已被 SAP 背书的标准通道

文章摘要:当前存在多个社区项目(如mcp-abap-adt、mcp-abap-abap-adt-api等)通过包装ABAP ADT能力为MCP Server,使AI开发工具能读取ABAP对象。这些项目技术上依赖ADT HTTP API或SAP官方ADT language server,但针对SAP S/4HANA Cloud Public Edition的完整适配仍存在挑战。SAP官方已通过VS Code扩展提供ADT MCP能力,而社区方案在云环境下需遵循ABAP Cloud的严格限制,仅能访问已授权的开

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 87

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Android NDK——初识协程(Coroutine)和libco的简单介绍使用

文章大纲引言一、协程Coroutine概述二、协程的优势三、C语言主流的协程库简介1、协程的切换2、libco2.1、libco概述2.2、libco 的使用说明2.2.1、co_create函数创建并初始化协程对象2.2.1.1、声明一个协程对象类型的指针2.2.1.2、调用co_create函数创建初始化协程对象2.2.2、coctx_swap进行协程上下文切换2.3、libco的简单应用 引言 协程不是进程或线程,其执行过程更类似于子例程,或者说不带返回值的函数调用。 一个程序可以包含多个协程,可以对

最美不过,心中有梦,身旁有你! 1605

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

[转]协程 及 Libco 介绍

2015-7-21阅读32 评论0 libco 是腾讯开源的一个协程库,主要应用于微信后台RPC框架,下面我们从为什么使用协程、如何实现协程、libco使用等方面了解协程和libco。   why协程 为什么使用协程,我们先从server框架的实现说起,对于client-server的架构,server最简单的实现: while(1) {accept();recv

abcd1f2的专栏 892

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

libco简介

好久都没在优快云上发博客了,大概两年了吧,看着以前写的博客,感觉自己更像是个前端工程师了,其实工作上我应该算是后端的吧。最近换了一份工作,新公司用到一个叫Colib的库,也在GitHub上开源了,虽然开源之后并没有人怎么维护,但这里面的代码的确也在线上用,这里面的思想也是挺有趣儿的,就研究了一下,也算是和后端相关了 https://github.com/Tencent/libco  1. 协...

ZZ的博客 1万+

C++ 开源协程库 libco——原理及应用

1 导论 使用 C++ 来编写高性能的网络服务器程序,从来都不是件很容易的事情。在没有 应用任何网络框架,从 epoll/kqueue 直接码起的时候尤其如此。即便使用 libevent, libev 这样事件驱动的网络框架去构建你的服务,程序结构依然不会很简单。为何会这样?因 为这类框架提供的都是非阻塞式的、异步的编程接口,异步的编程方式,这需要思维方 式的转变。为什么 golang 近几年能够...

cool grass's blog 5333

libco协程库上下文切换原理详解

念桥边红药,年年知为谁生 ​ —— 杨州慢 姜夔 缘起libco 协程库在单个线程中实现了多个协程的创建和切换。按照我们通常的编程思路,单个线程中的程序执行流程通常是顺序的,调用函数同样也是 “调用——返回”,每次都是从函数的入口处开始执行。而libco 中的协程却实现了函数执行到一半时,切出此协程,之后可以回到函数切出的位置继续执行,即函数的执行可以被“拦腰斩断”,这种在函数任

奔跑的企鹅 1万+

动态原理图 协程_一文彻底弄懂C++开源协程库libco——原理及应用

视频解析:1 导论使用 C++ 来编写高性能的网络服务器程序,从来都不是件很容易的事情。在没有应用任何网络框架,从 epoll/kqueue 直接码起的时候尤其如此。即便使用 libevent, libev这样事件驱动的网络框架去构建你的服务,程序结构依然不会很简单。为何会这样?因为这类框架提供的都是非阻塞式的、异步的编程接口,异步的编程方式,这需要思维方式的转变。为什么 golang 近几年能够...

weixin_31091881的博客 904
上一篇: 从事前端开发必须要了解的CSS原理
下一篇: Zookeeper开发常见问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值