阻塞I/O,当用户程序执行read,线程会被阻塞,一直等待内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read才会返回。

阻塞与非阻塞I/O_数据

非阻塞I/O,非阻塞的read请求在数据未准备好的情况下立即返回,可以继续往下执行,此时应用程序不断轮询内核,直到数据拷贝到应用程序缓冲区,read调用才可以获取到结果。

阻塞与非阻塞I/O_应用程序_02

访问管道或socket时,如果设置了O_NONBLOCK标志,那么就表示使用的是非阻塞I/O的方式访问,而不做设置,默认的是阻塞I/O。

应用程序每次轮询内核的I/O是否准备好,有点傻乎乎,因为轮询的过程中,应用程序啥也做不了,只是在循环。为了解决这个问题,I/O多路复用技术就出来了,如select、poll,它们通过I/O事件分发,当内核数据准备好时,再以事件通知应用程序进行操作。

阻塞与非阻塞I/O_数据_03

实际上,无论是阻塞I/O、非阻塞I/O,还是基于非阻塞I/O的多路复用,都是同步调用因为它们在read调用时,内核将数据从内核空间拷贝到应用程序空间,过程是需要等待的,也就是说这个过程是同步的,如果内核实现的拷贝效率不高,read调用就会在这个同步过程中等待比较长的时间。

真正的异步I/O内核数据准备好数据从内核态拷贝到用户态这两个过程都不用等待。

当发起aio_read后,就立即返回,内核自动将数据从内核空间拷贝到应用程序空间,这个拷贝过程同样是异步的,内核自动完成的,和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作,具体过程如下图:

阻塞与非阻塞I/O_数据_04