IO通信模型

习惯上,同步往往和阻塞联系在一起,异步和非阻塞联系在一起。实际上这两者是不同的概念,阻塞与非阻塞表述了一个任务在处理问题时的不同状态,是一个点的概念,在任务达到那个点时,根据阻塞或非阻塞进行不同操作。而同步与异步是段的概念,如果是同步则这段程序将在主线程执行,如果是异步则类似多线程的行为。

1.同步与异步


同步(Synchronous)和异步(Asynchronous),在一次方法调用中,如果采用同步的方式,若此方法未完成则整个程序无法进行其他步骤,日常的串行代码类似同步机制,需要一步一步执行。如果再一次方法调用中,进行方法调用后,无需等待方法执行完成即可进行下一步操作,方法在另外一条线上执行不影响本程序,则类似于异步机制。

2. 阻塞和非阻塞


任务在执行的过程中,由于资源不足,而处在一种等待的状态,是阻塞。阻塞状态会一直等待到资源等满足后再执行并返回。非阻塞是指,如果资源满足则进行,如果资源不满足,则返回一个执行不成功的信息,并不等待。

3. IO通信操作中的阻塞与非阻塞


IO通信主要包括:对外部设备的读写、对磁盘内容的读写、socket的读写等操作。这些操作主要分为两个部分:

1)等待IO设备响应任务
2)从IO设备处读取或向IO设备中写入内容

这两个操作都涉及到阻塞或非阻塞概念。
对于阻塞IO而言,等待IO设备响应时会一直等待它直到响应或超时为止。对于非阻塞IO而言,等待IO设备响应时如果发现它不能及时响应则会返回一个未响应信息。

4. IO通信操作中的同步与异步


IO通信主要包括:对外部设备的读写、对磁盘内容的读写、socket的读写等操作。这些操作主要分为两个部分:

1)等待IO设备响应任务
2)从IO设备处读取或向IO设备中写入内容

第一步根据响应情况分为阻塞和非阻塞两种状态,第二步根据情况分为同步与异步两种概念,如果任务程序主动去内核读取或写入数据,主线程因此停滞则为同步IO。
而异步IO是由内核进程引导,内核进行完成了第二部的读写操作,把最后的结果返回给主线程,整个读写过程不是在用户线程上进行,而是在内核上完成,用户进程最后得到通知,这种IO通信叫做异步IO。

5. 五类IO模型


5.1 阻塞IO模型

最传统的IO模型,是java中IO类采用的方法,等待设备时采用阻塞方法,读写信息时进行同步操作。对于以前的串行程序,阻塞IO足够了,时效低下是难免的。

5.2 非阻塞IO模型

顾名思义,当IO设备表示条件不满足时程序会返回一个信息,但为了实现此次IO操作,非阻塞程序需要另外的循环来不断确认IO可操作,这样也会导致CPU效率降低。

5.3 多路复用IO模型

JDK1.4中NIO的IO模型,是一种较为智能的IO模型。在多路复用IO中会有一个线程不断的轮询所有的IO请求操作,如果发现其中的一个处于可用状态则进行IO通信读写操作。在JavaNIO中,是通过selector.select()去查询每个通道是否有到达事件,如果没有事件,则一直阻塞在那里,因此这种方式会导致用户线程的阻塞。

多路复用IO类似于多线程+阻塞IO操作,但是不同的是它只用了一个线程去轮询所有的线程中的IO,效率更高。但也隐含问题,如果一个线程进行中需要完成的任务过多则会导致其他的方法IO不能得到连接。

5.4 信号驱动IO模型

在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个信号函数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用IO读写操作来进行实际的IO请求操作。

实际上信号驱动是一种类似于异步+同步的操作,之所以说第一步是异步而不是阻塞或非阻塞,实际上是因为这一步放给内核去完成,程序几乎不用考虑第一步操作。

5.1 异步IO模型

异步IO模型几乎是最好的一种模型,因为在这种模型下两个阶段都不需要用户操作,是一种类似完全异步的状态,用户在发起IO请求后就可以完全不用关心了,可以去执行其他操作。内核会完成接下来的所有事情,一直到2步操作全部完成才会把结果返回给用户。

注意,异步IO是需要操作系统的底层支持,在Java 7中,提供了Asynchronous IO。

前面四种IO模型实际上都属于同步IO,只有最后一种是真正的异步IO,因为无论是多路复用IO还是信号驱动模型,IO操作的第2个阶段都会引起用户线程阻塞,也就是内核进行数据拷贝的过程都会让用户线程阻塞。

6. 线程池概念

在普通多线程模式下,来了client,服务器就会新建一个线程来处理该client的读写事件。这样随着用户的增多,可能导致连接数量不够用,严重的可能会直接导致服务器崩溃。

因此,为了解决这种一个线程对应一个客户端模式带来的问题,提出了采用线程池的方式,也就说创建一个固定大小的线程池,来一个客户端,就从线程池取一个空闲线程来处理,当客户端处理完读写操作之后,就交出对线程的占用。因此这样就避免为每一个客户端都要创建线程带来的资源浪费,使得线程可以重用。

但是线程池也有它的弊端,如果连接大多是长连接,因此可能会导致在一段时间内,线程池中的线程都被占用,那么当再有用户请求连接时,由于没有可用的空闲线程来处理,就会导致客户端连接失败,从而影响用户体验。因此,线程池比较适合大量的短连接应用。

因此便出现了下面的两种高性能IO设计模式:Reactor和Proactor。

6.1 Reactor

  
在Reactor模式中,会先对每个client注册感兴趣的事件,然后有一个线程专门去轮询每个client是否有事件发生,当有事件发生时,便顺序处理每个事件,当所有事件处理完之后,便再转去继续轮询。类似于多路复用IO模型。

6.2 Proactor

在Proactor模式中,当检测到有事件发生时,会新起一个异步操作,然后交由内核线程去处理,当内核线程完成IO操作之后,发送一个通知告知操作已完成,可以得知,异步IO模型采用的就是Proactor模式。但是这种模型对内核要求高,在连接数不多且任务执行频繁的情况下,可以采用这种方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值