01、协程预先铺垫
--协程这一章比线程更加复杂,需要和socket那两章混合起来学习学习
02、并发 并行
--并发:一个时间段内【不是一个时间点】,运行多个程序。但是每一时刻cpu中只能有一个程序在执行,那么这些执行的程序就是处于并发状态的。
--并行:同一时刻,多个代码同时运行在多个cpu上,代码处于并行状态
03、同步 异步
--同步:当出现IO操作时,必须等待IO操作返回时才继续执行的操作称为同步。不涉及到IO操作时不需要考虑是否同步
--异步:不需要等待IO操作执行完毕返回结果,即可往下执行程序称之为异步操作。
--多线程就是典型的异步操作,它在启动之后直接能够得到一个返回对象
--这里的IO操作需要学习操作系统之后才能理解,不能简单视为存取文件。像爬虫 || 向服务器发请求 || 调用某个部署好的程序等都可以视为IO操作
04、阻塞 非阻塞
--阻塞:调用函数时,当前进程被挂起。比如我们调用多线程是通过阻塞的方式,使得我们在接收到结果时才继续执行当前进程,但是多线程时异步的。也就是说不论是同步还是异步方式执行程序,都不会影响我们阻塞当前进程
--非阻塞:调用函数时当前线程不被挂起,继续执行。同样也和同步异步关系不大
05、同步 异步 与 阻塞 非阻塞 的辨别
--同步 异步 可以视为一种消息通信机制
--阻塞 非阻塞 可以视为一种函数调用机制
06、IO多路复用 -- c10k问题
--如何让一台 1Ghz cpu | 2G内存 | 1gbps网络环境下 的服务器同时为1万个客户同时提供FTP服务
--显然使用1万个线程是不合乎现实情况的,服务器会崩溃掉
--这里就需要借用:同步异步 阻塞非阻塞 并发 io多路复用等方法混合使用解决该问题
07、unix下的5中I/O模型
--阻塞式IO:最基本的,也是编程中经常涉及到的
--非阻塞式IO:进一步讲解socket编程时会讲解到
--IO多路复用:
--信号驱动式IO:使用极少,不讲
--异步IO (POSIX的aio_系列函数):
--阻塞式IO图解说明:引用自 unix网络编程,recvfrom表示调用IO接口资源,并获取数据
--阻塞式IO尽管编程非常顺利,但是浪费了大量的cpu等待时间,效率低下
--非阻塞式IO图解说明:
--非阻塞式IO:如果后续代码依赖于前面代码的执行,此使非阻塞式IO需要等待前面代码执行完毕。此使效率甚至不如阻塞式IO方式,
例如在socket连接时,建立连接三次握手需要时间,即使没有阻塞也需要判断是否连接建立成功。因此无法直接继续执行代码
--对于内核 和 APP内存使用的注意:
--内核自己的内存[更加底层] 和 APP运行时申请的内存不是一个
--内核的内存是不能够让APP直接访问的
--web返回数据先保存在内核内存,之后由内核内存拷贝一份给需要使用的APP
--非阻塞式IO可能出现轮询查IO数据获取的状态情况,为了能够节约cpu资源,让数据返回到内核内存中后系统自己主动告诉程序数据准备好了,以避免对cpu资源的浪费。这里就出现了io多路复用
--IO多路复用:实际就是涉及这三个函数 -- select poll epoll
--select函数:查询内核内存中是否拿到了返回的响应数据
--select函数是阻塞的,如果内核中没有一个socket或文件句柄准备好时,socket实际上会一直阻塞在这里
通过以上可以看出 IO多路复用 被归结于 非阻塞式 是不正确的
--注:这个和轮询查询状态不一样,select可以监听多个socket和文件句柄,一旦有某一个已准备完毕即刻会被返回。有了这样一种属性,select就可以实现高并发而轮询是做不到的
--select通过监听多个socket和文件句柄实现并发,但是对于从内核内存中复制数据到APP内存这一段路来说仍然无法避免时间消耗
--信号驱动式IO:这种方式使用极少,可以不做了解
--异步IO:这个才是真正意义上的异步,但是很多异步框架使用的还是IO多路复用技术,异步IO相对而言不够技术成熟
--aio_read:相对于select函数节省了内核内存复制到APP内存的时间
08、select poll epoll三种同步IO方式解释
--select说明:
--poll
--epoll:其实现使用到了红黑树
09、epoll并不一定代表比select好,一般遵照如下标准
--并发高且连接活跃度低时,epoll效果比select好
--对于一个服务器应用,例如nginx。它随时会接受请求并断开,直到后台将结果返回
--并发低但是连接活跃度高时,epoll效果比select差
--游戏连接,只要连上就会一直处于连接状态发送游戏数据。此时就是并发低但连接活跃度高