1.微信libco协程库源码分析
2.[libco] libco 定时器(时间轮)
3.libco栈自动扩容
微信libco协程库源码分析
微信后台开发常用的libco协程库,是一种罕见的将C/C++协程应用于大规模生产环境的成功案例。相较于coroutine,libco在性能上表现出调度千万级协程的能力。它的优势主要体现在以下几个方面:更高效的协程上下文切换:libco通过自编汇编代码,仅保存和交换必要的运费模板源码寄存器和栈信息,与ucontext相比,显著提升了切换效率,据测试,其效率大约是ucontext的3.6倍。
自动处理IO阻塞:libco能自动切换到其他协程,包括处理三方库的世系图源码阻塞IO调用,如mysqlclient,通过Linux的hook技术和epoll机制无缝协作。
灵活的栈管理:支持共享或独立栈空间,用户可自定义协程栈大小,以适应不同的需求。
高效协作与通信:提供类似pthread的接口,便于协程间通信,而且支持协程嵌套创建,直观模拟了调用栈的运行过程。
在使用上,libco允许零改造的地区溯源码将阻塞IO调用异步化,并且在协程的维护和资源使用上,有着丰富的运营经验,如限制协程栈大小、提倡池化使用以及区分计算密集和网络密集任务。 尽管libco在开源活跃度上有所欠缺,但其开发者正在内部尝试引入新特性,如事件回调和类golang的channel,未来有望为社区带来更多改进。总的来说,libco以高性能和易用性展示了协程的强大潜力。[libco] libco 定时器(时间轮)
libco定时器采用数组+双向链表的猎手专注源码核心数据结构,类似于哈希表,通过空间换时间的策略,实现高效事件处理。该设计被称为“时间轮”,数组默认大小为一分钟内,用于保存即将到期的事件数据。相同到期时间的事件会被保存在双向链表中,当时间到达时,所有即将到期的事件将一起被取出处理。
对于超过一分钟的到期事件,libco通过取模路由机制,xstream源码分析将它们与一分钟内到期的事件耦合在一起,当取出来后,再进行检查,若事件未到期,则将其重新写入。
一般而言,应用中的超时事件多在1分钟以内,对于超出了这个时间范围的事件处理虽然可能显得笨拙,但在代码维护上代价较小。
libco定时器的结构设计巧妙,数组的下标表示毫秒单位时间,当前时间对应的下标stTimeout_t.llStartIdx,随着时间的推移,沿顺时针方向读写数据。这种设计使得时间轮能够高效地管理时间线上的事件。
在源码分析、缺点以及小结方面,libco定时器的实现细节和技术考量丰富,但整体上,它的设计在特定范围内展现出了高效性,尽管存在一些小的缺点,但这并不影响其整体表现,是值得推崇的实现方案。
libco栈自动扩容
Libco,由微信开源的协程库,其运行原理在许多文章中有详细介绍,这里不再赘述。每个协程执行时需要栈空间,当栈空间接近满载时,如何处理?直接让其崩溃显然不可取。本文针对libco源码进行了一些修改,使其在私有栈模式下具备自动扩容的能力。
当协程运行时,进入每个业务逻辑函数都可能消耗栈空间,导致栈满。因此,我们设定一个警戒值(如%),当栈空间低于此值时,触发扩容。利用G++编译器的-finstrument-functions特性,可以在每个函数的入口和返回点插入hook,避免对核心函数的不必要的监控。
在函数入口处,通过汇编指令获取栈顶地址,检查剩余空间。如果不足%,则执行扩容逻辑。扩容过程中,首先暂停当前协程co,切换到一个专门的协程co_x,它负责进行扩容操作。
co_x的初始化涉及创建新协程并指定其执行函数。接下来的co_grow_stack函数负责实际扩容,它会创建一个新的堆空间,大小为原栈空间的两倍,并确保新栈的rbp和rsp指向正确位置。同时,会递归修正原栈空间中的函数rbp和可能存在的栈内引用。
扩容结束后,清理原栈空间,更新co上下文中的栈指针,并在新栈空间保护页写入特定值,完成整个扩容过程。