NIO的Channel与DMA
IO大致分为
阻塞IO模型:也就是进程会一直阻塞,直到数据拷贝完成(拷贝当然是由网卡拷贝到内核态的内存空间,或者反之,这样做很大原因为了安全),坏处占用内存
非阻塞IO模型:当所请求的IO操作没有完成时,进程不会阻塞,直接返回,过一段之间再去询问,坏处是浪费CPU时间
IO复用模型:实现对多个I端口进行监听,主要用select和epoll
select: 缺点:最大并发数限制,因为一个进程能打开的FD是有限制的,所以造成监听数量有限制,也可以更改,但循环遍历会造成On的遍历。默认1024
效率问题:也就是每次需要扫描所有fd。
内核空间用户空间的拷贝问题,select采用了内存拷贝法,让内核吧FD消息通知给用户空间。且每次调用都会将fd集合从用户态拷贝到内核态。
epoll:改掉了以上缺点: 无最大连接数,只管活跃的FD(相当于有个只存储活跃fd的链表,这样遍历就极大减少时间复杂度),用了共享内存空间的方式解决了拷贝开销问题。 每个fd关联有对应的callback函数,活跃fd时主动调用
只拷贝一次fd到内核空间,不用每次调用时拷贝。
epoll和select本质都是同步IO,读写过程是阻塞的
DMA:DMA是一种快速传送数据的机制,数据传递可以从适配卡到内存,反正就是为了提升传输的速度
channel:类似于IO源与目标打开的连接
1. DMA是为了解放在IO操作时每一个字符都需要由CPU来管理传输, 在接到网卡中断时, cpu会初始化DMA, 打个比方, 你在打游戏,
可是门铃响了, 外卖到了, 你new 了一个girl friend 告诉她, 你定的什么外卖, 数量多少, 需要放在那里, 然后你继续好好打游戏, 其他交由她去完成(去的快递, 放入指定位置, 校验是否完成), done之后, 会回来中断你打游戏, 你就可以去吃外卖了, 节省你的精力
明白了DMA就好理解NIO的Channel了吧.
I/O通道控制方式与DMA方式的异同点:
通道控制方式与DMA方式类似,也是一种以内存为中心,实现设备和内存直接交换数据的控制方式。
通道控制方式与DMA方式类似,也是一种以内存为中心,实现设备和内存直接交换数据的控制方式。
与DMA方式不同的是,在DMA方式中,数据的传送方向、存放数据的内存始址以及传送的数据块长度等都由CPU控制,而在通道方式中,这些都由通道来进行控制。另外,DMA方式每台设备至少需要一个DMA控制器,一个通道控制器可以控制多台设备。ps:引用
多路复用模型
刚开始每次来一个请求都会中断, 交给kernel处理, 然后创建一个线程去完成数据的读取操作, 主线程继续循环等待连接, 坏处, 每一次连接都会有系统调用, 开销太大, 并且线程同样是宝贵资源
selector 模型 既然每次连接都中断这样不好, 那我就攒多一点调用系统调用, 将文件描述符fd存储在内核中, 然后每次遍历,全部fd, 返回可读可写状态的fd , 然后用户线程完成读写操作
在内核中创建一个epoll空间用来保存连接的fd
epoll 模型. 每次在内核中遍历fd也是一笔不小的开销, 利用硬件的物理中断, 网卡发出中断请求之后, 拿到fd去内核中找到, 返回可用状态的fd给用户完成读写操作, 是同步
redis 因为是单线程, 既要完成LRU, 存取 等操作 , 所以不会阻塞, 是循环
nginx是epoll之后就会阻塞, 多线程
零拷贝
mmap 在内核中和内存一块共享区域, 少了一次拷贝, 但只适合不用加工的数据, 直接返回给用户