Skip to content

异步I/O

阻塞I/O

操作系统在进行I/O操作时需要一定的时间,而阻塞I/O会等待I/O结果的返回,才会向下执行代码 ,导致cpu在等待的时候浪费了资源,并且阻塞了代码的执行

非阻塞I/O

非阻塞I/O在进项操作的时候会立即返回,但是不包含数据结果,如果想要数据结果,需要再次调用I/O读取文件描述符

为了得到数据结果,需要重复调用I/O读取文件描述符来判断是否操作完成,这种重复调用的操作叫做轮询

文件描述符

操作系统内核在进项文件的I/O操作时,通过文件描述符进行管理,而文件描述符类似于应用程序于系统内核之间的凭证

应用程序如果需要进行I/O调用,需要先打开文件描述符,然后在更具文件描述符去实现文件的数据读写

轮询

现存的轮询技术:

  • read :最原始、性能最低的一种,重复调用来检查I/O状态完成完整数据的读取 ,在得到最终数据前,cpu一直耗用在等待

  • select :他是read基础上改进的,通过对文件描述符上的时间状态来进行判断,并且有长度限制(数组),同时只能检查1024个文件描述符

  • poll : 对select的改进,取消了长度限制(链表)

  • epoll :利用事件机制,在I/O完成之后,通过事件通知,执行回调,并且在等待I/O完成时,将会进行休眠,不浪费cpu

异步I/O

异步I/O利用多线程的方式来实现

主线程负责代码的执行,当遇到I/O时,将I/O操作交给另外一个线程(I/O线程)

通过让I/O线程采用阻塞I/O或者非阻塞I/O加轮询技术来完成数据的获取,然后利用线程之间的通信将数据传给主线程

node的异步I/O

node中在处理到I/O时,采用异步I/O的方式

在碰到I/O时,先封装好请求对象、参数和回调函数,然后将请求对象放入异步I/O*中的线程池中等待执行

在有可用线程时,执行I/O操作,等待结果并将结果放入请求对象中,然后通知调用完成,将请求对象放在I/O的任务队列里,等待事件循环执行

然后node的事件循环执行到I/O事件的时候,取出请求对象中的回调函数执行

异步I/O: 不同平台采用不同的实现方式,liunx采用epoll实现,windows由内核(iocp)直接提供,node的libuv通过判断平台,采用不同的方式