IO包括两个过程:1、发起IO请求,2、执行IO操作
IO操作有两种(读/写)
读过程,一个是等待数据的过程(数据通过网关到达系统空间),一个是拷贝数据的过程(数据从系统空间写入用户内存)
写过程:一个是拷贝数据的过程(数据从用户内存写入系统空间),数据通过系统空间传到网关
1、同步:执行一个操作后,进程触发一个IO操作并等待或轮询查看IO操作是否完成,完成之后才可以做其他操作。
(同步在拷贝的过程,是用户线程自行读取数据)
2、异步:执行一个操作后,进程触发一个IO操作,然后立即返回,可以去执行其他操作,IO会交给内核去进行,等完成后会受到通知
(异步在拷贝的过程是由内核主动写入用户内存的,写完之后会通知用户线程)
3、阻塞:(cpu线程调度)进程给CPU传达一个任务之后,一直等待CPU处理完成,然后才执行后面的操作。
4、非阻塞:进程给CPU传达任务后,继续处理后续的操作,隔断时间再来询问之前的操作是否完成。
阻塞/非阻塞针对io的第一步,即发起io请求的过程,同步/异步针对io操作的第二步,即进行io操作。
BIO(同步阻塞io):一个线程处理一个请求,每次发起io请求都要创建一个线程,这个线程执行完这个操作后才能干别的事情。(注意:可以同时进行多个io操作,但是要创建多个线程)。
如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
通道和流很相似,通道支持读和写,流只支持读或写
通道从buffer中获取数据,通道传递数据到buffer
适用:连接数目比较小且固定的架构
NIO(同步非阻塞io):一个线程处理多个请求,但是请求之后的io操作是同步的,依然要一个一个执行。
客户端发送的请求都会注册到多路复用器上,当轮询到哪个请求要进行io操作是才创建一个线程去处理。
适用:连接数目多且连接比较短(轻操作)的架构
AIO(异步非阻塞io):不需要使用额外的io线程,使用回调函数函数实现,read/write操作都是异步的,操作完成后会主动调用回调函数。当io操作完成后应用程序会收到通知
客户端发送的请求都直接由内核处理,处理完成后会调用回调函数通知应用程序启动线程进行后续处理。
适用:连接数目多且连接比较长(重操作)的架构
操作系统提供了一些接口来支持多路复用io
select,poll,epoll的区别
select(底层实现:数组)与poll(链表)都是时间复杂度O(n),因为这两个只能返回是否有流在进行IO操作,然后还需要占用cpu时间片去轮询哪些流在进行IO操作,但是select的最大连接数是1024,poll没上限。而epoll(哈希表)(event poll)则不同,它是复杂度O(1),直接返回在执行IO操作的流,不需要轮询。
不一定epoll更好,因为若请求数量较少,且请求的活跃度高,那么使用select和poll更好,因为epoll的通知机制需要很多回调函数。