https://www.zhihu.com/question/32163005
https://segmentfault.com/a/1190000003063859#articleHeader6
IO模式
对于一次IO访问,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间;
网络模式:
- 阻塞 I/O(blocking IO)
- 非阻塞 I/O(nonblocking IO)
- I/O 多路复用( IO multiplexing) 只不过process是被select这个函数block,而不是被socket IO给block
- 异步 I/O(asynchronous IO)
IO 多路复用:多个Sock复用一根网线这个功能是在内核+驱动层实现的
多路网络连接复用一个io线程
多路复用,一条路可以很多人同时走的路
最传统的多进程并发模型 (每进来一个新的I/O流会分配一个新的进程管理
I/O多路复用 (单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流,是尽量多的提高服务器的吞吐能力
在同一个线程里面, 通过拨开关的方式,来同时传输多个I/O流
ngnix会有很多链接进来, epoll会把他们都监视起来,然后像拨开关一样,谁有数据就拨向谁,然后调用相应的代码处理
epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。
在 select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一 个文件描述符,内核向进程返回一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait() 时便得到通知。
- epoll 现在是线程安全的。
- epoll 现在不仅告诉你sock组里面数据,还会告诉你具体哪个sock有数据,你不用自己去找了。
----------------------------------------------------------------------------------------------------------------
IO模式一般分为同步IO和异步IO. 同步IO会阻塞进程, 异步IO不会阻塞进程.
目前linux上大部分用的是同步IO, 异步IO在linux上目前还不成熟, 不过windows的iocp算是真正的异步IO。
同步IO又分为阻塞IO, 非阻塞IO, IO多路复用. What? 同步IO明明会阻塞进程,为什么也包括非阻塞IO?
因为非阻塞IO虽然在请求数据时不阻塞, 但真正数据来临时,也就是内核数据拷贝到用户数据时, 此时进程是阻塞的.
那么这些IO模式的区别分别是什么? 接下来举个小例子来说明. 假设你现在去女生宿舍楼找自己的女神, 但是你只知道女神的手机号,并不知道女神的具体房间
先说同步IO的情况,
1. 阻塞IO, 给女神发一条短信, 说我来找你了, 然后就默默的一直等着女神下楼, 这个期间除了等待你不会做其他事情;
2. 非阻塞IO, 给女神发短信, 如果不回, 接着再发, 一直发到女神下楼, 这个期间你除了发短信等待不会做其他事情;
3. IO多路复用, 是找一个宿管大妈来帮你监视下楼的女生, 这个期间你可以做其他的事情,IO复用又包括 select, poll, epoll 模式. 那么它们的区别是什么?
3.1 select大妈 每一个女生下楼, select大妈都不知道这个是不是你的女神, 她需要一个一个询问, 并且select大妈能力还有限, 最多一次帮你监视1024个妹子
3.2 poll大妈不限制盯着女生的数量, 只要是经过宿舍楼门口的女生, 都会帮你去问是不是你女神
3.3 epoll大妈不限制盯着女生的数量, 并且也不需要一个一个去问. 那么如何做呢? epoll大妈会为每个进宿舍楼的女生脸上贴上一个大字条,上面写上女生自己的名字, 只要女生下楼了, epoll大妈就知道这个是不是你女神了, 然后大妈再通知你.
上面这些同步IO有一个共同点就是, 当女神走出宿舍门口的时候, 你已经站在宿舍门口等着女神的, 此时你属于阻塞状态
接下来是异步IO的情况
你告诉女神我来了, 然后你就去王者荣耀了, 一直到女神下楼了, 发现找不见你了, 女神再给你打电话通知你, 说我下楼了, 你在哪呢? 这时候你才来到宿舍门口;
-----------------------------------------------------------------------------------------------------------------
io分为磁盘io和网络io,这里说的是网络io。我们知道计算机之间传输数据是流传输。一台计算机网络io只会有一个。
这里说单进程
在最基本的c/s demo中,send/recv就是在一条io通道收发数据,这就是基本的网络io,但是这种操作是不能“填满”io的,也就是说大部分io资源你没有用,仅仅有一个io操作,当然你可以开多进程或多线程,代价可想而知
此时出现了io多路复用,自己的话翻译一下,复用网络io从而有多个io操作能在网络io中执行。
linux下网络io使用socket套接字来通信,普通io模型只能监听一个socket,而io多路复用可同时监听多个socket
io多路复用避免阻塞在io上,原本为多进程或多线程来接收多个连接的消息变为单进程或单线程保存多个socket的状态后轮询处理
实现io多路复用需要函数来支持,就是你说的linux下的select/poll,epoll以及win下 iocp 和 BSD 的 kqueue
简单说epoll和select/poll最大区别是
1.epoll内部使用了mmap共享了用户和内核的部分空间,避免了数据的来回拷贝
2.epoll基于事件驱动,epoll_ctl注册事件并注册callback回调函数,epoll_wait只返回发生的事件避免了像select和poll对事件的整个轮寻操作。
nginx中使用了epoll,是基于事件驱动模型的,由一个或多个事件收集器来收集或者分发事件,epoll就属于事件驱动模型的事件收集器,将注册过的事件中发生的事件收集起来,master进程负责管理worker进程
--------------------------------------------------------------------------------------------------
一个epoll场景:一个酒吧服务员(一个线程),前面趴了一群醉汉,突然一个吼一声“倒酒”(事件),你小跑过去给他倒一杯,然后随他去吧,突然又一个要倒酒,你又过去倒上,就这样一个服务员服务好多人,有时没人喝酒,服务员处于空闲状态,可以干点别的玩玩手机。至于epoll与select,poll的区别在于后两者的场景中醉汉不说话,你要挨个问要不要酒,没时间玩手机了。io多路复用大概就是指这几个醉汉共用一个服务员。
-----------------------------------------------------------------------------------------------------
Q:
那这样子,在读取socket1的数据时,如果其它socket有数据来,那么也要等到socket1读取完了才能继续读取其它socket的数据吧。那不是也阻塞住了吗?而且读取到的数据也要开启线程处理吧,那这和多线程IO有什么区别呢?
A:
1.CPU本来就是线性的 不论什么都需要顺序处理 并行只能是多核CPU
http://2.io多路复用本来就是用来解决对多个I/O监听时,一个I/O阻塞影响其他I/O的问题,跟多线程没关系.
3.跟多线程相比较,线程切换需要切换到内核进行线程切换,需要消耗时间和资源. 而I/O多路复用不需要切换线/进程,效率相对较高,特别是对高并发的应用nginx就是用I/O多路复用,故而性能极佳.但多线程编程逻辑和处理上比I/O多路复用简单.而I/O多路复用处理起来较为复杂.