开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
IO模型
1.阻塞IO:调用IO操作的时候,如果缓冲区空或者满了,调用的进程或者线程就会处于阻塞状态直到IO可用并完成数据拷贝。
2.非阻塞IO:非阻塞等待,每隔一段时间就去检测IO事件是否就绪,没有就绪就可以做其他事。调用IO操作的时候,内核会马上返回结果,如果IO不可用,会返回错误,此时可以根据errno区分这两种情况(eagain、ewouldblock)。这种方式下进程需要不断轮询直到IO可用为止,但是当进程从内核拷贝数据时是阻塞的。
3.信号驱动IO:linux用套接口进行信号驱动IO,安装一个信号处理函数,进程继续运行并不阻塞,当IO时间就绪,进程收到SIGIO信号。然后处理IO事件。
4.IO多路复用:有select/poll/epoll。同时对多个文件描述符进行读操作、写操作的IO函数进行检测。知道有数据可读或可写时,才真正调用IO操作函数。一旦某个描述符IO就绪(读就绪或者写就绪),就能够通知进程进行相应的IO操作,否则就将进程阻塞在select或者epoll语句上。
5.异步IO:在检测IO是否可用和进程拷贝数据的两个阶段都是不阻塞的,进程可以做其他事情,当IO完成后内核会给进程发送一个信号。linux中,可以调用aio_read函数告诉内核描述字缓冲区指针和缓冲区的大小、文件偏移及通知的方式,然后立即返回,当内核将数据拷贝到缓冲区后,再通知应用程序。
eagain:由于read/recv立即返回,但是此时并没有数据可读,就会返回这个错误。
eintr:指操作被中断唤醒,需要重新读/写。
ewouldbolck:用于非阻塞模式,不需要重新读或者写
阻塞I/O,非阻塞I/O,信号驱动I/O和I/O复用都是同步I/O?
同步I/O指内核向应用程序通知的是就绪事件,比如只通知有客户端连接,要求用户代码自行执行I/O操作,异步I/O是指内核向应用程序通知的是完成事件,比如读取客户端的数据后才通知应用程序,由内核完成I/O操作。
同步阻塞IO:
优点:应用的程序开发非常简单;在阻塞等待数据期间,用户线程挂
起。在阻塞期间,用户线程基本不会占用CPU资源。
缺点:一般情况下,会为每个连接配备一个独立的线程;反过来说,就
是一个线程维护一个连接的IO操作。在并发量小的情况下,这样做没有什么问题。但是,当在高并发的应用场景下,需要大量的线程来维护大量的网络连接,内存、线程切换开销会非常巨大。因此,基本上阻塞IO模型在高并发应用场景下是不可用的。
优缺点:
非阻塞IO:
优点:每次发起的IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会阻塞,实时性较好。
缺点:不断地轮询内核,这将占用大量的CPU时间,效率低下。类似于自旋
IO多路复用:
优点:与一个线程维护一个连接的阻塞IO模式相比,使用select/epoll
的最大优势在于,一个选择器查询线程可以同时处理成千上万个连接(Connection)。系统不必创建大量的线程,也不必维护这些线程,从而大大减小了系统的开销。
缺点:本质上,select/epoll系统调用是阻塞式的,属于同步IO。都需
要在读写事件就绪后,由系统调用本身负责进行读写,也就是说这个读写过程是阻塞的。
异步IO:
缺点:应用程序仅需要进行事件的注册与接收,其余的工作都留给了操作系统,也就是说,需要底层内核提供支持。