目录
阻塞 blocking
应用进程一直在等待read的返回结果。这种模型效率是不高,但是编程非常简单。
非阻塞 non-blocking
非阻塞:在数据未就绪状态下,它是不断的返回。并不会像阻塞一样一直等待数据准备好,他是不断返回返回值,可以通过返回值进行判断,返回值为0且error==EAGAIN就是一个正常的返回。
阻塞非阻塞都是同步操作。
lO复用 IO multiplexing
数据从未就绪到就绪,我们调用lO复用接口,数据就绪以后呢,我们根据具体的发生事件的fd进行相应的IO。它的好处就是一个线程调用一个lO复用接口,它可以监听很多很多的一个socket的fd,不像上边的阻塞跟非阻塞,一个应用进程或一个应用线程一次只能去处理一个socket,浪费进程或者线程,提高并发能力。
一个IO复用可以监听多个套接字,当多个套接字有数据的话就是数据可读或者可写,IO复用接口会给应用程序返回一个可读可写的socketfd列表,再根据这个列表去完成相应读写操作。
IO复用是一个同步的操作。
信号驱动 signal-driven
信号驱动,它调用相应的方法,注册SIGIO信号处理程序。相当于协商了一个通知的方式,系统调用调sigaction,注册了一下SIGIO信号。信号它的这个处理程序相当于就是回调操作,A向B注册,B返给A注册成功消息,A可以处理其他逻辑,B准备好数据后再通知A,这一过程是异步的。
数据就绪后,读取数据的过程仍然要调用read去读,这一过程是需要我们应用程序自己去把内核中的数据搬到我们的buffer中的,是一个同步的过程。
信号儿处理程序在第一阶段数据准备阶段是异步的,在第二个阶段数据读取是同步的。与非阻塞IO的区别在于,它提供了消息通知机制,不需要用户进程不断的轮巡检查,减少了系统API调用次数,提高了效率。
这里边说的不断的轮巡检查就是像非阻塞模式用户进程不断的轮询检查或者IO复用设置的timer out参数让它不断的判断是不是超时返回。当检查返回值等于0且error==EAGAIN的时候,会再次调用read或者是IO复用接口去查看内核的数据是否准备就绪,每次调用都需要消耗资源和时间的,信号驱动减少了系统调用次数,提升了效率。
异步IO asynchronous
异步IO,数据就绪,还有数据读写,整个过程不耗费应用程序和应用进程或者应用线,这个线程继续执行,就是它完全可以去做其他事情,它只要事先通过aio_read来告诉内核。我应用程序的一个缓冲区buffer、通知的信号、以及我对哪个socket感兴趣。
把这些告诉内核,然后内核给你返回一下收到,然后应用程序就可以自己去做其他事情了,内核准备好数据也不会打扰应用线程,内核会再把这个数据拷贝到最开始aio_read指定的用户空间buffer缓冲区里边,拷贝完了内核再通过事先约定好的信号通知应用程序。
信号驱动IO和多路复用IO的区别:
- 信号驱动I/O通过信号来通知应用程序进行I/O操作,而I/O复用通过系统调用和事件集合来监听和通知就绪的文件描述符。
- 信号驱动I/O通常适用于少量的文件描述符,而I/O复用适用于同时监听多个文件描述符的场景。
- 信号驱动I/O需要应用程序设置信号处理函数来响应事件,而I/O复用通过系统调用返回就绪的文件描述符,应用程序可以在主循环中处理这些就绪的事件。
- I/O复用在效率上通常优于信号驱动I/O,因为信号的处理需要发生上下文切换,并且信号在高负载情况下可能会丢失。
AIO、BIO、NIO、多路复用IO
AIO异步非阻塞IO:
- 在进行读写操作时,请求会被提交后立即返回,不等待操作完成。
- 当操作完成时,系统会通过事件或回调来通知应用程序。
- 这种模式可以使得线程不被阻塞,从而可以处理其他任务。
BIO同步阻塞IO:
- 在进行读写操作时,线程会被阻塞,直到操作完成(或者发生错误)。
- 为了提高并发能力,需要为每个连接创建一个新的线程,但这会导致在大并发下线程过多,资源消耗大。
NIO同步非阻塞IO:
- 当请求读写操作时,如果数据未准备好或未能立即写入,该操作会立即返回,并告知当前无法完成读写。
- 与BIO不同的是,线程在此过程中不会被阻塞,而是可以继续执行其他任务。
多路复用IO:
这是NIO中的一种技术,允许单个线程监控多个输入输出通道(可能是文件,套接字等)。当其中一个通道准备好进行读取或写入时,线程就开始处理它。常见的多路复用技术有 select、poll、epoll等。