导语

因为网络相关的抽象和实现确实做得非常棒, 很多时候我们都将asio视为一个网络库, 而忽略了它其实一直做得非常好的通用任务调度这部分的功能. 而本系列文章我们将区别于大部分asio的学习资料, 我们将暂时抛开asio外围的平台相关网络实现等内容, 对它的任务调度部分的实现做详细的剥析.  系列文章的大部分内容最开始是作为executions系列文章中, 对比executions稍显薄弱的scehduler实现而存在的背景资料. 但通过一段时间的executions实践, 介于它本身并未正式通过标准, 依赖的concepts等内容compiler的报错等支持都暂未很好的跟上, 我们将目光转向了更容易落地的asio通用任务调度, 已经被标准和各大编译器良好支持的coroutine特性, 作为本阶段重点推进的异步调度实现基础, 感觉这部分可挖掘的实际价值和潜力都比较大, 所以将asio调度器系列的资料重新整理, 理清自己思路的同时, 也希望对大家有所帮助.

1. ASIO版本现状简介

ASIO是一个久经迭代的库, 所以版本比较多, 不同版本的差异也比较大, 在开始具体的讲述前, 我们先来看一下ASIO的版本情况, 也方便大家知道我们所选用的ASIO版本, 以及它与最新的版本的差异所在.


ASIO从1.17(2020)开始尝试向当时的executions提案靠拢, 当时的executions提案从最原始的Api数量爆炸的版本, 转向了通过引入property对api复杂度进行简化的版本, 众所周知的, 引入property的executions提案依然表现不尽如人意,现在的executions提案已经彻底抛弃了基于property的这套提案, 但 asio 的作者作为executions提案的发起者之一, 还是在按相关提案的思路在迭代整体的asio库, 所以代码中大量存在了property相关的设施和使用, 这里简单列出一些相关的示例代码:

对于系统本身特别复杂, 需要适应的场景特别多的情况 , 这种设计本身确实会简化部分业务侧的使用理解复杂度, 原来对多种不同Api的记忆, 变成了property的选择.


 但其实对于库本身的实现来说, 我们也容易看到,  利用property对多种并发泛式进行约束的方式, 本身就具备一定的复杂度, 尤其是对于asio本身来说, 我们会发现原来的实现变得更难理解了. 对于库的构建来说, 很难说它提供的是一个简单易扩展的机制.  


 这点从tag_invoke提案中拿自身跟property对比的相关示例也能看得出来两者表达能力上的落差. 个人认为, 同样是对库的定制和对泛型的支持的目的, 基于cpo的tag invoke本身应该是更值得选择的, 而property本身我感觉比cpo的理解成本要更高, 用于构建库代码, 也会导致库代码本身的复杂度变高, 在它没有成为C++标准的一部分之前, 这种复杂度的引入肯定是不那么合适的.


  这种复杂度的增加我们从当前asio 1.22代码仓库可以比较容易看出, 主体功能变化不大(对比1.16版本), 但引入了相当多的代码用于在兼容低版本c++的情况下对property等基础功能进行支持,  导致整体代码复杂度剧增, 但实际带来的便利性基本看不到. 如果抛开对新特性的预研本身, 这些调整对asio的版本迭代来说, 可以说跟优雅本身相去甚远的.


 对比向早期execution的靠拢, asio 对c++20 coroutine的支持还是可圈可点的, 这个从作者近期的实例代码讲解中也能感受到, 像awaitable的"||" "&&"等支持, 很好的扩展了协程中多任务处理的语义, 更容易用更少的代码实现出简单易理解, 易维护的异步代码.


 回到scheduler本身, 我们本篇的重点是asio的scheduler部分实现, 这部分在asio加入property机制前后其实变化不大, 但由于加入property后, 相关的scheduler部分耦合了大量的property相关的机制和代码, 带来了比较高的复杂度, 本文我们直接选择不包含property的asio1.16的代码进行展开, 方便以更低的复杂度分析相关的实现.


asio调度器实现 - 总览篇-腾讯云开发者社区-腾讯云 (tencent.com)