写点什么

Code Like Sync, Works Like Async

  • 2020-10-20
  • 本文字数:2042 字

    阅读完需:约 7 分钟

Code Like Sync, Works Like Async

前言.

打从敲下"Hello World!",咱们算入行了。我开始写代码,和用计算器差不多:


  • 输入:1 + 1

  • 结果:2


代码一路顺着走,不开叉。


生涯第 1 个波折,是学到条件判断,像这样:


  • a = 1,b = 1

  • if a + b = 2 print "这都知道?"else print “答对了”


代码开始有不同走向,有点绕,还能驾驭。


再后来就遇到人生大哉问:妈和媳妇一起掉河里,你救谁?


翻译一下,如何同时运行代码 A 和代码 B(并行)?


为一起救,我学过各种泳姿:


  • 开始用 “定时器/软中断”挺好,不过随着媳妇数(代码块)的增多,猝!

  • 后来折腾“事件驱动/状态机”,就活在连跳/回调地狱里,最终为个 delay 而累猝!

  • 最后“多线程”还行…还活着。


焦头烂额,终于 hold 住。


可人生问题哪止这些,后来更大问题是 3 字:“没钱”


“多线程”虽好,太费钱(资源消耗大)、太折腾(竞争成本高),很多场景受限:


  • 浏览器:没有多线程

  • 嵌入式 MCU:实时性要求高、RAM 受限,甚至没有 RTOS

  • 大链接数 server:微信后台

  • 游戏:魔兽世界


吐血。


小品文已过,咱们言归正传。

1.

近些年,很多编程语言都修订标准,新增 2 个关键字 async/await:


  • 直接包含:C#/JavaScript/Rust/Dart

  • 其它语言(golang/erlang/lua…)没直接包含,也提供类似机制 ,比如 Go goroutine


所有目的,都是为更好的支持异步编程,不约而同的加强 Coroutine。


Coroutine(协程)是老东西(比 UNIX 都早),近些年的广泛使用有其背景:


  • 大量线程用不起(服务器或嵌入式),或者没有线程(浏览器或 MCU 裸机)

  • 然而,异步需求在,开源库 API 设计成异步 IO 渐变主流

  • 可异步代码太难搞,程序一膨胀,不是回调地狱就是全程乱跳。。。

  • 由此不约而同想:代码能不能写起来像同步,跑起来像异步?

  • 做梦之余一看,这不是就是 Coroutine 吗?好好,不止第三方库,要语言层支持,加 promise,再加 async/await


嗯,这段像瞎掰,实际是典型 JavaScript 开发者心态,其它也类似。


远的不说,做嵌入式开发,也常被异步 IO 编程(基于中断/消息/事件)搞得焦头烂额,我也想要“Code like sync, works like async”。


可 C/C++如何做 Coroutine 呢?

2.

方案 1


基于用户态 Scheduler(微信后台方案)


Coroutine 是简单的东西,第一反应就是拿用户态 Scheduler 实现。


即任务切换时,完成真实的换栈:



任务运行上下文(context)可以简视:寄存器/栈信息,当每个协程任务放弃(yield)时,执行 context 切换。看起来和 OS 线程没区别,实际是有的:


  • 所有 Coroutines 共享 1 个 CPU 线程,相互无抢占(协作式,竞争成本低)

  • Coroutine 更轻,尽管 Linux 中单线程只需约 4KB(1 页),然而 1 个 Coroutine 只 0.1KB

  • Coroutine 切换快(约 100T),在多数平台上消耗时间在纳秒级/微秒级


对大量链接的服务器后台,上述优势明显。可以参见腾讯开源协程库: libco。


这是对调用者干净的实现,编程没有限制,PC 端主流协程库都如此实现:


  • libco(微信)/Boost.Context(C++准标准)/libaco/coroutine


换栈的手段也不局限汇编,有系统库或第三方:


  • posix 中 context/Windows 中 fiber/C 标准中 setjump 等。


尽管如此,可对嵌入式编程意义很小:


  • RTOS 中 Task 实现类似,内存消耗/切换成本已经很低

  • RTOS 中 Task 亦可配置成协作式(非抢占)

  • 每种 CPU 都需要移植,等价于再实现 Scheduler,意义不大


方案 2


基于标签语法糖(switch 或 goto 扩展)


这是借用预编译宏和标签,大玩语法游戏的套路。


目前所有类似实现(如 Protothread),都基于 Simon Tatham 的文章,这里简要 1 种核心:



仔细看上述代码,它是合法的。在 switch/case 间,插入不同的语句,用不同 case 分割。由此换个视角看,count 可视为状态索引,每次进入时会恢复到代码对应位置。这是一种不基于换栈的任务切出/切回方式。


把上述 switch/case 手段用宏 crBegin/crFinish/crReturn 包装下,下面两段带 while(1)的死循环代码,就可以在 1 个线程中并发执行:



这是 Coroutine 实现的最轻方式,优点:


  • 完全标准 C 实现,跨平台

  • 每个 Coroutine 只需要额外 1 字节 - 2 字节内存

  • Task 切换无成本


不过,不知道大家发没发现,局部变量该怎么办?


没有换栈,无法用局部变量,必须 static 静态化。由此,这种方式受限明显:


  • 如果用 static 变量,会导致函数无法重入

  • 如果不用 static,就必须传参类似 ctx 参数来代替局部变量


看的出来,让调用者有些难受。


由此,Contiki OS 又对上述方法改良并包装,并用这种机制实现整个操作系统的多任务。


它的代码值得一读,除了这部分,其它模块(uIP/GUI/Timer/Mem)都很漂亮。

3.

大家看的出来,嵌入式系统上 1 和 2 还不够完美,有没有更好的方案?希望:


  • 只用 C99 实现,完全跨平台/跨架构

  • 内存消耗要远小于线程,额外消耗在几个字节内

  • 可以使用局部变量(至少表面上)

  • 对调用者友好,类似其它语言 async/await 的方式


显然需要新方案。


这里卖个关子,感兴趣的朋友可以留言讨论,请持续关注我们公众号哦~


作者介绍


王相宇,滴滴两轮车硬件技术部


本文转载自公众号普惠出行产品技术(ID:gh_ed6841067977)。


原文链接


Code Like Sync, Works Like Async


2020-10-20 14:002738

评论

发布
暂无评论
发现更多内容

天翼云推荐新人返好礼,最高返利千元

天翼云开发者社区

极速调取客户保单,YRCloudFile 助力保险存储架构升级

焱融科技

AI 存储 NAS 数字金融

源码解读预告 |TiFlash DeltaTree 引擎设计及实现解析!

TiDB 社区干货传送门

关于 WordPress 你了解多少?

海拥(haiyong.site)

WordPress 5月月更

【刷题第14天】两个链表的第一个公共节点

白日梦

5月月更

AIRIOT物联网低代码平台如何配置OPC UA驱动?

AIRIOT

【高并发】什么是ForkJoin?看这一篇就够了!

冰河

并发编程 多线程 高并发 协程 异步编程

【活动报名】TiDB 社区天津站 Meetup 要来啦!

TiDB 社区干货传送门

OceanBase 源码解读(十一):Location Cache 模块浅析

OceanBase 数据库

oceanbase 源码解读

青藤入选信通院“数据安全推进计划”成员单位

青藤云安全

数据安全 信通院

先是IPV6,再是WI-FI7你都清楚这是什么吗?

郑州埃文科技

ipv6 IP地址

阿里云联合鼎捷软件发布云上数字工厂解决方案,实现云MES系统本地化部署

阿里云弹性计算

数字化转型 MES系统 中小企业 云盒

论道原生:走进可观测性

Daocloud 道客

云原生 可观测性 OpenTelemetry

dfs专项练习题

工程师日月

DFS 5月月更

宜搭5月更新:跨应用数据读写能力升级,AI组件内测开放

一只大光圈

SysAK 应用抖动诊断篇—— eBPF又立功了! | 龙蜥技术

OpenAnolis小助手

Linux 工具 内核 ebpf 龙蜥技术

计算机网络概述

工程师日月

计算机网络 5月月更

springboot集成activiti整套方案()

金陵老街

Vue ERP Activiti spring-boot

5.26直播预告|《观见话题》第一期:跨境组网与加速上云的硬核解法

观测云

【LeetCode】数组中的第K个最大元素Java题解

Albert

LeetCode 5月月更

生命科学领域下的医药研发通过什么技术?冷冻电镜?分子模拟?IND?

GPU算力

ECSM隐私协议

潇潇雨歇

美团二面:为什么Redis会有哨兵?

Java全栈架构师

Java 数据库 redis 程序员 面试

All in ONE!博睿数据重磅推出一体化智能可观测平台

博睿数据

博睿数据 IT运维 ONE平台

4月券商App行情刷新及交易体验评测报告,7家券商入围领导者象限

博睿数据

性能测试 系统运维 博睿数据 券商排行

Authing 被世界经济论坛评选为 2022 技术先锋企业

Authing

身份云 科技 Idaas 科技企业

Authing 身份云招聘:增长黑客

Authing

招聘 科技

英特尔庄秉翰:推动5G释放数字经济潜能,拥抱“银发时代”美好生活

科技之家

520特别企划 | Z世代进入婚恋市场,婚恋交友行业会有什么变化?​

易观分析

Z世代

七、云原生日志审计

穿过生命散发芬芳

日志 5月月更

普渡科技宣布成立“PUDU-X”创新基金,为青年工程师筑梦未来

Geek_2d6073

Code Like Sync, Works Like Async_编程语言_王相宇_InfoQ精选文章