OWenT's blog
  • Introduction
  • About Me
  • 2020
    • 近期对libatapp的一些优化调整(增加服务发现和连接管理,支持yaml等)
    • xresloader转表工具链增加了一些新功能(map,oneof支持,输出矩阵,基于模板引擎的加载代码生成等)
    • 在游戏服务器中使用分布式事务
    • libcopp接入C++20 Coroutine和一些过渡期的设计
    • libatbus 的大幅优化
    • nftables初体验
    • 容器配置开发环境小计
  • 2019
    • PALM Tree - 适合多核并发架构的B+树 - 论文阅读小记
    • 跨平台协程库 - libcopp 简介
    • C++20 Coroutine 性能测试 (附带和libcopp/libco/libgo/goroutine/linux ucontext对比)
    • 尝鲜Github Action
    • 一些xresloader(转表工具)的改进
    • protobuf、flatbuffer、msgpack 针对小数据包的简单对比
    • 协程框架(libcopp) 小幅优化
    • Excel转表工具(xresloader) 增加protobuf插件功能和集成 UnrealEngine 支持
    • Anna(支持任意扩展和超高性能的KV数据库系统)阅读笔记
    • C++20 Coroutine
    • libcopp merge boost.context 1.69.0
    • Google去中心化分布式系统论文三件套(Percolator、Spanner、F1)读后感
    • Rust玩具-企业微信机器人通用服务
  • 2018
    • 使用ELK辅助监控开发测试环境服务质量和问题定位
    • Webpack+vue+boostrap+ejs构建Web版GM工具
    • 2018年的新通用伪随机数算法(xoshiro / xoroshiro)的C++(head only)实现
    • Rust的第二次接触-写个小服务器程序
    • 理解和适配AEAD加密套件
    • atsf4g-co的进化:协程框架v2、对象路由系统和一些其他细节优化
    • 协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比
    • 可执行文件压缩
    • 初识Rust
    • 使用restructedtext编写xresloader文档
    • atframework的etcd模块化重构
    • C++的backtrace
  • 2017
    • ECDH椭圆双曲线(比DH快10倍的密钥交换)算法简介和封装
    • protobuf-net的动态Message实现
    • pbc的proto3接入
    • atgateway内置协议流程优化-加密、算法协商和ECDH
    • 整理一波软件源镜像同步工具+DevOps工具
    • Blog切换到Hugo
    • libcopp v2的第一波优化完成
    • libcopp(v2) vs goroutine性能测试
    • libcopp的线程安全、栈池和merge boost.context 1.64.0
    • GCC 7和LLVM+Clang+libc++abi 4.0的构建脚本
    • libatbus的几个藏得很深的bug
    • 用cmake交叉编译到iOS和Android
    • 开源项目得一些小维护
    • atapp的c binding和c#适配
    • 对象路由系统设计
    • 2016年总结
    • 近期的一个协程流程BUG
  • 2016
    • 重写了llvm+clang+libc++和libc++abi的构建脚本
    • atsf4g完整游戏工程示例
    • atframework基本框架已经完成
    • 游戏服务器的不停服更新
    • 对atbus的小数据包的优化
    • Android和IOS的TLS问题
    • pbc的一个陈年老BUG
    • boost.context-1.61版本的设计模型变化
    • 接入letsencrypt+全面启用HTTP/2
    • 理解Raft算法
    • libatbus基本功能及单元测试终于写完啦
    • 博客文章和文档迁移到gitbook
  • 2015
    • 博客文章和文档迁移到gitbook
    • 给客户端写得LRU缓存
    • 近期活动比较零散
    • 关于BUS通信系统的一些思考(三)
    • 针对Java JIT的优化(转表工具:xresloader)
    • libcopp更新 (merge boost 1.59 context)
    • 小记最近踩得两个C++坑
    • Redis全异步(HA)Driver设计稿
    • Vim常用命令
    • 关于firewalld和systemd的一些命令速记
    • Jenkins(hudson)插件记录
    • 我们的Lua类绑定机制
    • LLVM+Clang+Libcxx+Libcxxabi(3.6)工具链编译(完成自举编译)
    • 回顾2014
    • Android NDK undefined reference to ___tls_get_addr 错误
    • gitlab腾讯企业邮箱配置
  • 2014
    • 回顾2013
    • C++11动态模板参数和type_traits
    • C++又一坑:动态链接库中的全局变量
    • tolua++内存释放坑
    • [转]类似github的框架
    • Lua性能分析
    • 集成Qt Webkit 到cocos2d-x
    • Gitlab环境搭建小计
    • 近期研究VPN的一些记录(OpenVPN,pptp,l2tp)
    • LLVM + Clang + Libcxx + Libcxxabi 工具链编译
    • 关于BUS通信系统的一些思考(二)
    • 关于BUS通信系统的一些思考(一)
    • [libiniloader] Project
    • 记录一些在线编辑器
    • [WP Code Highlight.js] Project
    • 再议 C++ 11 Lambda表达式
    • 基于Chrome插件的开发工具链
    • [ACM] HDU 1006 解题报告
    • Linux 编译安装 GCC 4.9
    • 又碰到了这个解谜游戏,顺带记下地址
    • 简单C++单元测试框架(支持一键切到GTest或Boost.Test)
    • 捣鼓一个协程库
  • 2013
    • std和boost的function与bind实现剖析
    • 不知道是哪一年的腾讯马拉松题目 照片评级 解题报告
    • Lua 挺好用的样子
    • VC和GCC成员函数指针实现的研究(三)
    • VC和GCC成员函数指针实现的研究(二)
    • VC和GCC内成员函数指针实现的研究(一)
    • 一个C++关于成员变量偏移地址的小Trick
    • ptmalloc,tcmalloc和jemalloc内存分配策略研究
    • POJ 2192 Zipper HDU 2059 龟兔赛跑
    • 从Javascript到Typescript到Node.js
    • 网络编程小结
    • 试试Boost.Asio
    • Lnmp yum 安装脚本 (for CentOS)
    • ARM 交叉编译环境搭建
    • Linux 编译安装 GCC 4.8
    • [记录]虚拟硬盘的压缩|磁盘写零
  • 2012
    • Boost.Spirit 初体验
    • “C++的90个坑”-阅读笔记
    • AC自动机
    • C++ 标准过渡期
    • 程序员修炼之道 -- 阅读笔记
    • [转载]狼与哈士奇
    • C++ 新特性学习(八) — 原子操作和多线程库[多工内存模型]
    • C++ 新特性学习(七) — 右值引用
    • 理解Protobuf的数据编码规则
    • 忆往昔ECUST的ACM时代
    • Linux编译安装GCC 4.7
    • JSON显示库 -- showJson (Javascript)
    • C++ 新特性学习(六) — 新的字符串编码和伪随机数
    • C++ 新特性学习(五) — 引用包装、元编程的类型属性和计算函数对象返回类型
    • C++ 新特性学习(四) — Bind和Function
  • 2011
    • C++ 新特性学习(三) — Regex库
    • C++ 新特性学习(二) -- Array、Tuple和Hash库
    • C++ 新特性学习(一) -- 概述+智能指针(smart_ptr)
    • Linux 和 Windows PowerShell 常用工具/命令 记录
    • 非常帅气的Linq to sql
    • 2011 Google Code Jam 小记
    • C++总是很神奇
    • 大学生创新项目[国家级]经费使用记录
    • 常用官方文档整理
    • 我们学校的IPV6很不错嘛
  • 2010
    • 线段树相关问题 (引用 PKU POJ题目) 整理
    • 2010 ACM 赛前笔记
    • POJ PKU 2596 Dice Stacking 解题报告
    • POJ PKU 3631 Cuckoo Hashing 解题报告
    • POJ PKU 1065 Wooden Sticks 3636 Nested Dolls 解题报告
    • HDU 3336 Count the string 解题报告
    • Hash模板 个人模板
    • ZOJ 3309 Search New Posts 解题报告
    • POJ PKU Let's Go to the Movies 解题报告
    • 注册表常用键值意义
    • PKU POJ 1724 ROADS 解题报告
    • 《神奇古今秘方集锦》&《民间秘术大全》
    • PKU POJ 1720 SQUARES 解题报告
    • POJ PKU 2155 Matrix 解题报告
    • PKU POJ 1141 Brackets Sequence 解题报告
    • PKU POJ 2728 Desert King 解题报告
    • PKU POJ 2976 Dropping tests 解题报告
    • PKU POJ 3757 Simple Distributed storage system 解题报告
    • GCD Determinant 解题报告
    • Southeastern European 2008 Sky Code 解题报告
    • HDU HDOJ 3400 Line belt 解题报告
    • 线性筛法求质数(素数)表 及其原理
    • HDU HDOJ 3398 String 解题报告
    • 树状数组模块(个人模板)
    • 浙江理工 省赛总结 team62 By OWenT of Coeus
    • POJ PKU 3659 Cell Phone Network 解题报告
    • USACO 2008 March Gold Cow Jogging 解题报告
    • C#格式化输出(记录)
    • 参加有道难题笔记
    • POJ PKU 2446 Chessboard 解题报告
    • POJ PKU 1986 Distance Queries 解题报告
    • 计算几何算法概览[转载]
    • 关于差分约束(转载)
    • POJ PKU 2826 An Easy Problem?! 解题报告
    • 数论模板(个人模板)
    • 简易四则运算(ACM个人模板)
    • Catalan 数
    • The 35th ACM/ICPC Asia Regional Tianjin Site —— Online Contest 1009 Convex 解题报告
    • JQuery扩展插件--提示信息
    • ACM 计算几何 个人模板
    • 解析网站字符串型参数 Javascript QueryString 操作 TQueryString类
    • POJ PKU 1474 Video Surveillance 解题报告
  • 2009
    • 模式匹配(kmp)个人模板
    • 并查集 模板
    • POJ 3267 The Cow Lexicon 解题报告
    • C/C++语言常用排序算法
    • POJ 2606 Rabbit hunt 2780 Linearity 1118 Lining Up 解题报告
    • 打造最快的Hash表(转) [以暴雪的游戏的Hash为例]
    • ECUST 09年 校赛个人赛第六,七场总结
    • ECUST 09年 校赛个人赛第三场部分解题报告(A,D,F,I)
    • 牛顿迭代解方程 ax^3+bX^2+cx+d=0
    • 09年8月9日 ECUST ACM 练习赛总结
    • 连接最多点直线 (OWenT 个人模板)
    • 点到直线距离 和 线段间最短距离 (OWenT 模板)
    • ECUST 09年 校赛个人训练赛第五场总结
    • ECUST 09年 校赛个人赛第八场(最后一场)总结
    • 09年8月14日 ECUST ACM 练习赛总结
    • 矩阵相关 (增强中)
    • Prime最小生成树(个人模板)
    • 最长单调子序列 复杂度nlog(n)
    • POJ PKU 2549 Sumsets 解题报告
    • POJ PKU 3277 City Horizon 解题报告
    • 我的ACM生涯
    • POJ PKU 2528 Mayor's posters 解题报告
    • POJ PKU 2378 Tree Cutting 解题报告
    • POJ PKU 1990 MooFest 解题报告
Powered by GitBook
On this page
  • libcopp v2内存布局
  • 栈池
  • 性能对比
  • 压力测试机环境
  • 压力测试对比
  • 【协程数:1,栈大小16KB】 - 切换耗时对比
  • 【协程数:1000,栈大小2MB】 - 创建耗时对比
  • 【协程数:1000,栈大小2MB】 - 切换耗时对比
  • 【协程数:30000,栈大小64KB】 - 创建耗时对比
  • 【协程数:30000,栈大小64KB】 - 切换耗时对比

Was this helpful?

  1. 2018

协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比

Previousatsf4g-co的进化:协程框架v2、对象路由系统和一些其他细节优化Next可执行文件压缩

Last updated 5 years ago

Was this helpful?

很早就实现完成了v2版本,现在迁移进以后也把v2分支正式并入了主干。原来的版本切出到v1分支并且停止维护了。

libcopp v2内存布局

开发 v2版本的最大目的是优化allocator的接口和内存碎片。

原来的allocator虽然是可定制的,但是是内置的。每次创建一个allocator对象,不同allocator之间共享数据只能通过全局数据或者TLS数据。现在则可以传入allocator了。这也是为后续的共享栈池做准备。

其次就是优化结构布局以优化内存碎片问题。在v1版本里,一个很重要的设计要点是各项组件可拆卸,就是说一些设计模式层面的东西比如协程任务、任务管理、等待和依赖关系等是可选的。同时栈分配器也可以是多种选择,采用系统地址映射加保护帧、采用malloc或者自定义分配器。为了各项组件尽可能解耦和易于组合,模块间较少采用组合关系,较多采用了引用关系,原来的协程任务结构大致上是这样的。

可以看得出来一个协程运行的时候对象数量很多。这样的话碎片也很多,虽然现代化的malloc实现能大幅缓解碎片问题,但是终归是有一些开销。上面图里是一个比较完整的结构关系,实际使用中有些组件如果不需要是可以移除掉的,比如 cotask 相关的部分。

栈池

在压力测试过程中,我们发现其实相对于业务逻辑,协程的创建和切换的开销占比非常小。但是有一样的开销很高,那就是缺页中断。我们知道在Linux中,在内存地址被实际使用前,是不会有物理内存页映射进来的。在第一次访问未映射地址的时候(特别是协程第一次切入到执行栈),会触发一次缺页中断,然后由操作系统把实际物理页映射上去,然后再继续执行。这个缺页中断引起的开销是其他协程创建流程总和的大约10倍左右。所以为了减缓这种开销,我们引入了一个新的stack allocator - 栈池allocator。目前栈池的实现是一个比较简单的但基本可用版本,并且初步实现了可以根据负载自动调整池子大小的功能。这样在低负载服务中可以有效减少内存消耗,在高负载服务中也能提高复用率。

性能对比

从压测结果上看,v2版本对v1的CPU L1缓存命中率是有下降的。我们分析这是因为v1版本中对象是碎片化的关系。因为碎片化的对象底层有 jemalloc 的加持,导致即便是在手动构造的栈cache miss的压力测试中,由于我们压测的CPU的L1 cache是32KB=8way*64sets*64B的,导致访问前一个对象的时候,后一个对象还是有部分数据被加载到了缓存中,小对象的缓存命中率还是比较高。这其实也是不符合实际应用场景的。

因为一般情况下我们并不是为了跑分而优化,协程接口一般在切换上下文后逻辑会更加复杂。所以为了尽可能贴近实际应用,我们尽量构造cache miss的用例来评估性能。同时我们大部分项目上线的时候编译选项都是-O2,所以在压力测试的时候我们也尽量使用O2级别的编译优化(有些系统自带包会用O3),编译选项是 -O2 -g -DNDEBUG -ggdb -Wall -Werror -fPIC 。项目中一般会启用安全性较高的方案,所以我们的压力测试中,只要是可以定义栈分配的库,栈都使用mmap出来4K对齐的页和使用mprotect尾部的方式来维护栈空间。

压力测试机环境

环境名称

值

系统

Linux kernel 3.10.104(Docker)

CPU

E5-2630 v2 @ 2.60GHz * 12

L1 Cache

64Bytes*64sets*8ways=32KB

系统负载

1.27 1.29 1.17

内存占用

2.86GB(used)/2.84GB(cached)/2GB(free)

CMake

3.11.3

GCC版本

8.1.0

[1.67.0][10]

libco版本

0af0b89998f2f691208f530cacb799ed033098f6 (20180605)

libcopp

8ce6dfef26ccf6a1ecb55336dde18a6526f76666 (20170423)

压力测试对比

组件(Avg)

协程数:1 切换开销

协程数:1000 创建开销

协程数:1000 切换开销

协程数:30000 创建开销

协程数:30000 切换开销

栈大小(如果可指定)

16 KB

2 MB

2 MB

64 KB

64 KB

60 ns

3.7 us

91 ns

3.5 us

239 ns

60 ns

109 ns

90 ns

261 ns

238 ns

79 ns

4.2 us

124 ns

3.8 us

338 ns

80 ns

246 ns

126 ns

340 ns

335 ns

94 ns

7.1 us

180 ns

5.7 us

451 ns

94 ns

3.8 us

173 ns

4.0 us

558 ns

95 ns

3.8 us

1021 ns

3.8 us

1810 ns

-

3.8 us

6275 ns

4.0 us

6429 ns

197 ns

5.3 us

124 ns

2.3 us

441 ns

539 ns

7.0 us

482 ns

2.7 us

921 ns

464 ns

578 ns

538 ns

1.4 us

799 ns

linux ucontext

356 ns

4.0 us

431 ns

4.5 us

946 ns

【协程数:1,栈大小16KB】 - 切换耗时对比

{ "type": "horizontalBar", "data": { "labels": [ "libcopp", "libcopp+动态栈池", "libcopp+libcotask", "libcopp+libcotask+动态栈池", "libco+静态栈池", "libco(共享栈4K占用)", "libco(共享栈8K占用)", "libco(共享栈32K占用)", "libgo with boost", "ucontext", "goroutine", "libgo with ucontext" ], "datasets": [ { "label": "切换耗时对比【协程数:1,栈大小16KB】", "data": [ 60, 60, 79, 80, 94, 94, 95, 197, 356, 464, 539 ], "backgroundColor": [ "rgba(255, 99, 132, 0.5)", "rgba(54, 162, 235, 0.5)", "rgba(255, 206, 86, 0.5)", "rgba(75, 192, 192, 0.5)", "rgba(153, 102, 255, 0.5)", "rgba(255, 159, 64, 0.5)", "rgba(54, 192, 192, 0.5)", "rgba(92, 102, 255, 0.5)", "rgba(255, 232, 86, 0.5)", "rgba(22, 130, 303, 0.5)", "rgba(223, 67, 100, 0.5)", "rgba(223, 127, 32, 0.5)" ], "borderColor": [ "rgba(255, 99, 132, 1)", "rgba(54, 162, 235, 1)", "rgba(255, 206, 86, 1)", "rgba(75, 192, 192, 1)", "rgba(153, 102, 255, 1)", "rgba(255, 159, 64, 1)", "rgba(54, 192, 192, 1)", "rgba(92, 102, 255, 1)", "rgba(255, 232, 86, 1)", "rgba(22, 130, 303, 1)", "rgba(223, 67, 100, 1)", "rgba(223, 127, 32, 1)" ], "borderWidth": 1, "maxBarThickness": 5 } ] }, "options": {} }

【协程数:1000,栈大小2MB】 - 创建耗时对比

{ "type": "horizontalBar", "data": { "labels": [ "libcopp+动态栈池", "libcopp+libcotask+动态栈池", "goroutine", "libcopp", "libco+共享栈4K占用", "libco+共享栈8K占用", "libco+共享栈32K占用", "ucontext", "libcopp+libcotask", "libgo with boost", "libgo with ucontext", "libco+静态栈池" ], "datasets": [ { "label": "创建耗时对比【协程数:1000,栈大小2MB】(单位:纳秒)", "data": [ 109, 246, 578, 3700, 3800, 3800, 3800, 4000, 4200, 5300, 7000, 7100 ], "backgroundColor": [ "rgba(255, 99, 132, 0.5)", "rgba(54, 162, 235, 0.5)", "rgba(255, 206, 86, 0.5)", "rgba(75, 192, 192, 0.5)", "rgba(153, 102, 255, 0.5)", "rgba(255, 159, 64, 0.5)", "rgba(54, 192, 192, 0.5)", "rgba(92, 102, 255, 0.5)", "rgba(255, 232, 86, 0.5)", "rgba(22, 130, 303, 0.5)", "rgba(223, 67, 100, 0.5)", "rgba(223, 127, 32, 0.5)" ], "borderColor": [ "rgba(255, 99, 132, 1)", "rgba(54, 162, 235, 1)", "rgba(255, 206, 86, 1)", "rgba(75, 192, 192, 1)", "rgba(153, 102, 255, 1)", "rgba(255, 159, 64, 1)", "rgba(54, 192, 192, 1)", "rgba(92, 102, 255, 1)", "rgba(255, 232, 86, 1)", "rgba(22, 130, 303, 1)", "rgba(223, 67, 100, 1)", "rgba(223, 127, 32, 1)" ], "borderWidth": 1, "maxBarThickness": 5 } ] }, "options": {} }

【协程数:1000,栈大小2MB】 - 切换耗时对比

{ "type": "horizontalBar", "data": { "labels": [ "libcopp+动态栈池", "libcopp", "libcopp+libcotask", "libgo with boost", "libcopp+libcotask+动态栈池", "libco+共享栈4K占用", "libco+静态栈池", "ucontext", "libgo with ucontext", "goroutine", "libco+共享栈8K占用", "libco+共享栈32K占用" ], "datasets": [ { "label": "切换耗时对比【协程数:1000,栈大小2MB】", "data": [ 90, 91, 124, 124, 126, 173, 180, 431, 482, 538, 1021, 6275 ], "backgroundColor": [ "rgba(255, 99, 132, 0.5)", "rgba(54, 162, 235, 0.5)", "rgba(255, 206, 86, 0.5)", "rgba(75, 192, 192, 0.5)", "rgba(153, 102, 255, 0.5)", "rgba(255, 159, 64, 0.5)", "rgba(54, 192, 192, 0.5)", "rgba(92, 102, 255, 0.5)", "rgba(255, 232, 86, 0.5)", "rgba(22, 130, 303, 0.5)", "rgba(223, 67, 100, 0.5)", "rgba(223, 127, 32, 0.5)" ], "borderColor": [ "rgba(255, 99, 132, 1)", "rgba(54, 162, 235, 1)", "rgba(255, 206, 86, 1)", "rgba(75, 192, 192, 1)", "rgba(153, 102, 255, 1)", "rgba(255, 159, 64, 1)", "rgba(54, 192, 192, 1)", "rgba(92, 102, 255, 1)", "rgba(255, 232, 86, 1)", "rgba(22, 130, 303, 1)", "rgba(223, 67, 100, 1)", "rgba(223, 127, 32, 1)" ], "borderWidth": 1, "maxBarThickness": 5 } ] }, "options": {} }

【协程数:30000,栈大小64KB】 - 创建耗时对比

{ "type": "horizontalBar", "data": { "labels": [ "libcopp+动态栈池", "libcopp+libcotask+动态栈池", "goroutine", "libgo with boost", "libgo with ucontext", "libcopp", "libcopp+libcotask", "libco(共享栈8K占用)", "libco(共享栈4K占用)", "libco(共享栈32K占用)", "ucontext", "libco+静态栈池" ], "datasets": [ { "label": "创建耗时对比【协程数:30000,栈大小64KB】(单位:纳秒)", "data": [ 261, 340, 1400, 2300, 2700, 3500, 3800, 3800, 4000, 4000, 4500, 5700 ], "backgroundColor": [ "rgba(255, 99, 132, 0.5)", "rgba(54, 162, 235, 0.5)", "rgba(255, 206, 86, 0.5)", "rgba(75, 192, 192, 0.5)", "rgba(153, 102, 255, 0.5)", "rgba(255, 159, 64, 0.5)", "rgba(54, 192, 192, 0.5)", "rgba(92, 102, 255, 0.5)", "rgba(255, 232, 86, 0.5)", "rgba(22, 130, 303, 0.5)", "rgba(223, 67, 100, 0.5)", "rgba(223, 127, 32, 0.5)" ], "borderColor": [ "rgba(255, 99, 132, 1)", "rgba(54, 162, 235, 1)", "rgba(255, 206, 86, 1)", "rgba(75, 192, 192, 1)", "rgba(153, 102, 255, 1)", "rgba(255, 159, 64, 1)", "rgba(54, 192, 192, 1)", "rgba(92, 102, 255, 1)", "rgba(255, 232, 86, 1)", "rgba(22, 130, 303, 1)", "rgba(223, 67, 100, 1)", "rgba(223, 127, 32, 1)" ], "borderWidth": 1, "maxBarThickness": 5 } ] }, "options": {} }

【协程数:30000,栈大小64KB】 - 切换耗时对比

{ "type": "horizontalBar", "data": { "labels": [ "libcopp+动态栈池", "libcopp", "libcopp+libcotask+动态栈池", "libcopp+libcotask", "libgo with boost", "libco+静态栈池", "libco(共享栈4K占用)", "goroutine", "libgo with ucontext", "ucontext", "libco(共享栈8K占用)", "libco(共享栈32K占用)" ], "datasets": [ { "label": "切换耗时对比【协程数:30000,栈大小64KB】", "data": [ 238, 239, 335, 338, 441, 451, 558, 799, 921, 946, 1810, 6429 ], "backgroundColor": [ "rgba(255, 99, 132, 0.5)", "rgba(54, 162, 235, 0.5)", "rgba(255, 206, 86, 0.5)", "rgba(75, 192, 192, 0.5)", "rgba(153, 102, 255, 0.5)", "rgba(255, 159, 64, 0.5)", "rgba(54, 192, 192, 0.5)", "rgba(92, 102, 255, 0.5)", "rgba(255, 232, 86, 0.5)", "rgba(22, 130, 303, 0.5)", "rgba(223, 67, 100, 0.5)", "rgba(223, 127, 32, 0.5)" ], "borderColor": [ "rgba(255, 99, 132, 1)", "rgba(54, 162, 235, 1)", "rgba(255, 206, 86, 1)", "rgba(75, 192, 192, 1)", "rgba(153, 102, 255, 1)", "rgba(255, 159, 64, 1)", "rgba(54, 192, 192, 1)", "rgba(92, 102, 255, 1)", "rgba(255, 232, 86, 1)", "rgba(22, 130, 303, 1)", "rgba(223, 67, 100, 1)", "rgba(223, 127, 32, 1)" ], "borderWidth": 1, "maxBarThickness": 5 } ] }, "options": {} }

v2版本在这方面就有了一些优化。基本思路是每个协程执行的时候都必然会分配一个执行栈,那么其实我们在执行栈上开辟一块空间放这些对象(执行栈是自顶向下增长,所以可以放到栈空间的最后面)。同时还可以开辟出一块用户私有数据块,用于方便使用者可以存放一些 的私有数据,也不需要额外的动态分配。当然,各项组件的可自由组装和裁剪的特性也是必须保留的,我们的组织结构如下图所示:

版本

(20180216)

(依赖)

+静态栈池

(共享栈4K占用)

(共享栈8K占用)

(共享栈32K占用)

with boost

with ucontext

libcopp+libcotask比单纯的libcopp多了进程内唯一ID的分配、状态转换和维护、可调用对象和跳转函数直接的转换和事件响应,并且保证了线程安全。工程上一般会用libcotask,但是功能上libcopp才是和其他对比项类似的部分。在压力测试中,也没有包含和里系统函数hook的部分。

的作者已经不再建议使用共享栈所以我们没有压测的共享栈性能。采用锁实现了线程安全,我们压测过程中没有启动多线程所以测试结果也不包含线程等待的消耗。

仅支持静态栈池,并且静态栈池只是为了减少共享栈时的copy开销,所以也分别对模拟栈使用量为4K、8K和32K时模拟栈池耗尽时的压力测试,可以看到栈使用量较大时,切换的memcpy开销较大。但是在工程中,的栈池也不会只分配一个,所以项目中的真实消耗还是要看最终的命中率,如果栈池剩余量越大,性能更向第一组靠近,否则根据栈使用量向后面靠近。

libcopp/libcotask测试代码:

测试代码:

测试代码:

ucontext 测试代码:

测试代码:

总体来说,和还是很有优势的。特别是动态栈池,几乎可以让创建开销逼近上下文切换,可以放心地无脑创建协程了。这里面需要特别说明一下的是和。goroutine的切换并没有优势,但是创建性能还是挺高的,原因之一是我对不是很熟,不太清楚怎么让go的cachemiss掉,看起来它自带一些池子的功能。而是支持静态栈池的,如果静态的栈池足够大或者使用量不大的时候,也能有不错的切换性能(不需要memcpy栈),只是池子用完以后波动会很大。

[10]:

TrivialType
libco
libgo
libgo
libgo
libgo
libco
libco
libco
https://github.com/owt5008137/libcopp/tree/v2/sample
goroutine
https://gist.github.com/owt5008137/1842b56ac1edd5a7db54590d41af1c44#file-goroutine_benchmark-go
libco
https://gist.github.com/owt5008137/1842b56ac1edd5a7db54590d41af1c44#file-libco_benchmark-cpp
https://gist.github.com/owt5008137/1842b56ac1edd5a7db54590d41af1c44#file-ucontext_benchmark-cpp
libgo
https://gist.github.com/owt5008137/1842b56ac1edd5a7db54590d41af1c44#file-libgo_benchmark-cpp
libcopp
libcotask
goroutine
libco
go
libco
https://www.boost.org/users/history/version_1_67_0.html
Golang
1.10.2
Boost版本
libgo
libcopp
libcopp+动态栈池
libcopp+libcotask
libcopp+libcotask+动态栈池
libco
libco
libco
libco
libgo
libgo
goroutine(golang)
libcopp
atsf4g-co/tree/sample_solution
libcopp
1806-01.png
1806-02.png