赞
踩
对于后台开发我们一个重要问题即使用尽可能少的服务器资源处理海量的请求,除了我们再架构上做多机自动扩容外,我们还必须尽可能提高单机硬件的利用率(CPU利用率+IO利用率)
为了提高硬件的利用率往往我们采用三种技术路径:
多线程可以充分利用CPU的多核,实现真正的并行,它是操作系统的基础设施。但是线程是一个粗粒度、相对比较笨重的多任务的抽象机制,例如以下几个特点
操作系统中有两种IO:同步IO和异步IO(5种I/O模型)
同步IO:发起IO(比如read)后,CPU必须原地等待其结束,然后才能继续往下执行
异步IO:发起IO(比如read)前,会先注册一个回调函数;发起IO后,CPU无需原地等待其完成,而是继续往下执行;CPU收到IO完成的中断信号后,将调用回调函数处理IO完成后的剩下的工作
即:同步IO的逻辑直观,但是性能较低,仅适用少量IO;异步IO性能好,但是逻辑复杂,适用于大规模并发IO
ps:CPU执行速度是远大于IO响应速度的,若执行同步IO,到达某一个函数(read执行IO操作),这个函数执行5分种,那么当前线程就必须原地等待5分钟(忙等待),才能执行后续代码,这对于CPU资源十分浪费。但是在异步IO模式下,CPU和IO可以全速并行执行,使用率大大提高
多线程和异步IO的缺点即是协程的优点
ps:协程不是进程或线程,其执行过程更类似于子例程,或者说不带返回值的函数调用。我们知道多个线程相对独立,有自己的上下文,切换受系统控制;而协程也相对独立,有自己的上下文,但是其切换由自己控制,由当前协程切换到其他协程由当前协程来控制。
对于大多数后台程序面临的都是IO密集型任务,它的处理流程大致如下:
用以上三种方式怎么实现这种架构
架构 | 描述 |
多线程架构 | 侦听线程收到一个客户端请求之后创建一个工作线程(或从线程池种申请一个空闲的线程)处理该请求,工作线程发起同步IO后,原地等待其完成;然后向客户端返回请求 |
异步IO架构 | 工作线程从队列中取出一个请求之后,注册一个回调函数并发起一个异步IO;然后立刻返回,周而复始的处理下一个请求;IO完成后,回调函数负责向客户端返回结果 |
协程架构 | 工作线程从队列中取出一个请求之后,调用一个处理协程;然后立即返回,周而复始的处理下一个请求;处理协程负责发起IO;IO完成后,发起IO的处理协程向客户端返回请求结果 |
三种架构的对比
架构 | 特点 |
多线程 | 逻辑直观、容易实现,但不能充分利用后台服务器硬件资源,容易发生雪崩 |
异步IO | 逻辑杂乱、维护麻烦,但性能卓越,目前依旧是后台服务器的主流架构 |
协程 | 性能卓越且逻辑直观,是后台服务器架构的演进方向 |
协程和线程的实现很相似,每个线程都有一个对应的线程函数,每个协程也有一个对应的协程函数;线程函数和普通函数没有区别,但是协程函数和普通函数有区别。
普通函数:每次调用只能从第一条语句开始执行
协程函数:协程函数交出控制权后,可以再次从交出控制权的下一语句开始执行(类比多线程的调度方式)
ps:普通函数每次执行都会从入口进入,当A函数调用B函数,那么只有当B函数执行完毕才能再去执行A剩余的代码,函数做不到当B执行一半,再去调用A可以从A剩余部分往下执行(每次调用函数都会从函数入口重新开始)。但是协程就可以做到,这种方式和线程十分相似。因为调用普通函数时,调用方的返回地址、入口参数等信息都保存在栈上。函数返回后,栈上的信息会自动清除,所以每次调用普通函数都只能从第一条语句开始
ps:上面所描述的是协程实现的一般原理,根据实现方式不同,可分为有栈协程和无栈协程
技术路线:一个线程可以创建大量协程,每个协程都会保留一个私有栈,协程一旦执行到异步IO处,就会主动交出控制权。同一线程的所有协程以串行方式协作执行,没有数据争用的问题
有栈协程的特点
ps1:为了减少有栈协程的空间开销,有些协程框架用一个共享栈代替每个协程的私有栈。共享栈虽然降低了协程的空间开销,但却引进了栈拷贝的时间开销。
ps2:对称协程调度逻辑复杂,应用的场景有限,非对称协程是有栈协程的主流
有栈协程可通过操作系统提供的系统调用实现
OS | 系统调用 |
Linux | getcontext,setcontext,makecontext,swapcontext |
Windows | CreateFiber,ConvertFiberToThread,SwitchToFiber |
技术路线:将异步IO封装到协程函数中,协程函数发起异步IO后,立即保存执行环境,然后吧控制权交给调用方(Caller),调用方继续往下执行;异步IO完成后,负责处理IO完成事件的回调函数获得控制权,回调函数再把控制权转交给发起IO的协程,发起IO的协程首先恢复执行环境,然后从上一次交出控制权的下一条语句继续往下执行
无栈协程特点
ps:通过操作系统原子操作或者各种锁机制可以解决数据争用问题
链接:https://blog.csdn.net/Eunice_fan1207/article/details/91894192
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。