文章目录
协程设计原理与汇编实现
本文介绍了协程的概念、特征、优势、以及其实现原理。
1. 协程概念
协程是一种轻量级的用户态线程。它允许在单个线程内执行多个任务,使得程序可以在不同的函数之间灵活地切换,以便更好地利用 CPU 资源。这种机制特别适合 IO 密集型任务(如网络请求、文件读写)和异步编程场景。协程可以被暂停和恢复,避免了阻塞等待,同时不需要系统级线程的切换成本。
协程的实现在底层是由执行流的跳转切换机制实现的。一般情况,有一个协程调度器作为每个协程挂起时要切换回的代码。
应用场景:
- webserver
- kv存储
- 图床,网络层
同步和异步:
"同步"和"异步"主要是指在执行任务时,任务与调用方的相互关系。在同步操作中,调用方会等待任务执行完毕然后继续执行。在异步操作中,调用方会立即返回并继续执行后续的操作,不会等待任务执行完,任务执行完可以通过回调、事件等方式通知调用方。
异步的好处:
- 多线程并发,充分利用cpu,性能好。
异步的坏处:
- 代码复杂,不好理解,需要设置回调函数或者使用事件机制。
协程的好处:
- 同步的编程方式,实现异步的性能。
互联网中协程可能被用到的场景:
- 浏览器网页加载发送异步HTTP请求时可能用到了协程。
- 淘宝商店界面加载商品信息
- 直播界面加载评论和视频流
- 贴吧加载新的帖子回复
- bilibili异步加载新的回复
- 网络游戏中加载各种位置信息
- 微信聊天时,需要异步加载和发送信息
- 音视频通话异步加载流媒体
- chatgpt异步发送和接收问答消息
- github的git仓库托管服务器可能使用协程处理用户的push、pull等请求
2. 协程的实现
2.1 setjmp
setjmp
和 longjmp
提供了一种低级的非局部跳转机制,适用于需要在 C 程序中实现复杂控制流或异常处理的情况。但由于它们带来的复杂性和潜在风险,使用时需要小心,确保不会影响程序的可维护性和可读性。
代码示例:
#include <setjmp.h>
#include <stdio.h>
jmp_buf env1, env2, env3;
// coroutine1
void func1(void)
{
int cur = 0;
int ret = setjmp(env1);
if (ret == 0)
longjmp(env3, 1);
printf("func1: %d [%d]\n", ret, cur++);
if (ret < 20)
{
longjmp(env2, ++ret);
}
}
// coroutine1
void func2(void)
{
int cur = 0;
int ret = setjmp(env2);
printf("func2: %d [%d]\n", ret, cur++);
if (ret < 20)
{
longjmp(env1, ++ret);
}
}
int main()
{
int ret = setjmp(env3);
if (ret == 0)
func1()</