常见问题
1.同步 VS 异步
2.阻塞 VS 非阻塞
3 缓存 VS 缓冲
1.同步 VS 异步
同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)
所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由*调用者*主动等待这个*调用*的结果。
例子:
你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
异步则是相反,*调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在*调用*发出后,*被调用者*通过状态、通知来通知调用者,或通过回调函数处理这个调用。
你打电话问书店老板有没有《分布式系统》这本书,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。
java 主要就是多线程技术。
2.阻塞与非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
举例
你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。
5种类UNIX下可用的I/O模型
- 阻塞式I/O(BIO);
- 非阻塞式I/O;
- I/O复用(select,poll,epoll...)(NIO);
- 信号驱动式I/O(SIGIO);
- 异步I/O(POSIX的aio_系列函数)(AIO);
一个输入操作通常包括两个不同阶段:
(1)等待数据准备好;
(2)从内核向进程复制数据。
阻塞式I/O模型
把recvfrom函数视为系统调用,一般会发生从应用进程空间运行切换到内核空间中运行,然后再切换回来。
进程调用recvfrom,系统调用知道数据报到达且被复制到应用进程的缓存区中或者发生错误才返回。recvfrom返回后,应用进程开始处理数据报。
非阻塞式I/O:
进程把一个套接字设置成非阻塞是在通知内核,当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把进程投入睡眠,而是返回一个错误。
前三次调用recvfrom时没有数据可返回,返回EWOULDBLOCK错误。
第四次调用recvfrom时,已有一个数据报准备好,它被复制到应用进程缓冲区,于是recvfrom成功返回。当一个应用进程对一个非阻塞描述符循环调用recvfrom时,我们称之为轮询(polling)。应用进程持续轮询内核,已查看某个操作是否就绪。这样做,耗费大量CPU时间。
I/O多路复用:
虽然I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。如图
我们阻塞于select调用,等待数据报套接字变为可读。当select返回套接字可读这一条件时,我们调用recvfrom把所读数据报复制到应用进程缓冲区。
比较图6-3 和图6-1,IO复用并不显得优势,事实上由于select需要两个而不是单个系统调用,IO复用还稍有劣势。
select的优势在于可以等待多个描述符就绪。
与IO复用相对的是另一种IO模型,是多线程中使用阻塞式IO.两者区别:select阻塞在多个文件描述符上;多个线程(每个文件描述符一个线程,这样每个线程都可以自由地调用诸如recvfrom之类的阻塞式IO系统调用了)。
异步I/O
这类函数的工作机制是告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到用户空间)完成后通知我们。如图:
注意红线标记处说明在调用时就可以立马返回,等函数操作完成会通知我们。
对比
了解了I/O模型,再学习NIO相对容易多了。
JAVA领域
NIO是同步非阻塞(select)IO模型
AIO(NIO2)异步非阻塞IO模型
参考资源
http://yaocoder.blog.51cto.com/2668309/1308899
https://www.zhihu.com/question/19732473