为什么使用协程,我们先从server框架的实现说起,对于client-server的架构,server最简单的实现:
while(1) {accept();recv();do();send();}
串行地接收连接、读取请求、处理、应答,该实现弊端显而易见,server同一时间只能为一个客户端服务。
为充分利用好多核cpu进行任务处理,我们有了多进程/多线程的server框架,这也是server最常用的实现方式:
accept进程 - n个epoll进程 - n个worker进程
- accpet进程处理到来的连接,并将fd交给各个epoll进程
- epoll进程对各fd设置监控事件,当事件触发时通过共享内存等方式,将请求传给各个worker进程
- worker进程负责具体的业务逻辑处理并回包应答
以上框架以事件监听、进程池的方式,解决了多任务处理问题,但我们还可以对其作进一步的优化。
进程/线程是Linux内核最小的调度单位,一个进程在进行io操作时 (常见于分布式系统中RPC远程调用),其所在的cpu也处于iowait状态。直到后端svr返回,或者该进程的时间片用完、进程被切换到就绪态。是否可以把原本用于iowait的cpu时间片利用起来,发生io操作时让cpu处理新的请求,以提高单核cpu的使用率?
协程在用户态下完成切换,由程序员完成调度,结合对socket类/io操作类函数挂钩子、添加事件监听,为以上问题提供了解决方法。