- 当计算机在切换用户态,内核态时,他们是如何通知彼此有事件发生的呢;
- 其实有bio,nio,aio IO的通信,是这里面有很多阻塞,我们只能够通过多个线程来避免主线程的阻塞。
bio
如果有大量的连接过来,那服务器需要创建很多个线程与之对应,并且线程的创建也是需要消耗资源的,因为线程使用的栈是独占的(栈大小默认1MB),同时CPU的资源调度也是需要浪费。
nio
NIO可让您只使用一个(或几个)单线程管理多个通道(网络连接或文件),但付出的代价是解析数据可能会比从一个阻塞流中读取数据更复杂
aio
主要是包含io多路复用,有select,poll,epoll方式。
select 实现多路复用的方式是,
1、将已连接的 Socket 都放到一个文件描述符集合,
2、然后调用 select 函数将文件描述符集合拷贝到内核里,让内核来检查是否有网络事件产生,检查的方式很粗暴,就是通过遍历文件描述符集合的方式,当检查到有事件产生后,将此 Socket 标记为可读或可写,
3、接着再把整个文件描述符集合拷贝回用户态里,然后用户态还需要再通过遍历的方法找到可读或可写的 Socket,然后再对其处理。
poll 不再用 BitsMap 来存储所关注的文件描述符,取而代之用动态数组,以链表形式来组织,突破了 select 的文件描述符个数限制,当然还会受到系统文件描述符限制
epoll 通过两个方面,很好解决了 select/poll 的问题。
epoll 使用事件驱动的机制,内核里维护了一个链表来记录就绪事件,当某个 socket 有事件发生时,通过回调函数内核会将其加入到这个就绪事件列表中,当用户调用 epoll_wait() 函数时,只会返回有事件发生的文件描述符的个数,不需要像 select/poll 那样轮询扫描整个 socket 集合,大大提高了检测的效率。