同步or异步

1、什么是同步?什么是异步?编程

  同步:若是有多个任务要执行,这些任务必须逐个执行,一个任务的执行会致使整个流程的暂时等待,这些任务没有办法并发地执行;设计模式

  异步:若是有多个任务要执行,这些任务能够并发执行,一个任务的执行不会致使整个流程的暂时等待。服务器

  举个简单的例子:网络

  假若有一个任务包括两个子任务AB,对于同步来讲,当A在执行的过程当中,B只有等待,直至A执行完毕,B才能执行;而对于异步就是AB能够并发地执行,B没必要等待A执行完毕以后再执行,这样就不会因为A的执行致使整个任务的暂时等待。多线程

 

2、什么是阻塞?什么是非阻塞?并发

  阻塞:当某个任务在执行过程当中,发出一个请求操做,可是因为该请求操做须要的条件不知足,那么就会一直在那等待,直至条件知足;异步

  非阻塞:当某个任务在执行过程当中,发出一个请求操做,若是该请求操做须要的条件不知足,会当即返回一个标志信息告知条件不知足,不会一直在那等待。socket

  阻塞和非阻塞的区别关键在于当发出请求一个操做时,若是条件不知足,是会一直等待仍是返回一个标志信息。async

  举个简单的例子:性能

    假如我要读取一个文件中的内容,若是此时文件中没有内容可读,对于同步来讲就是会一直在那等待,直至文件中有内容可读;而对于非阻塞来讲,就会直接返回一个标志信息告知文件中暂时无内容可读。

    同步和异步的着重点在于多个任务的执行过程当中,一个任务的执行是否会致使整个流程的暂时等待;

    而阻塞和非阻塞的着重点在于发出一个请求操做时,若是进行操做的条件不知足是否会返会一个标志信息告知条件不知足。

 

3、什么是阻塞IO?什么是非阻塞IO

  一般来讲,IO操做包括:对硬盘的读写、对socket的读写以及外设的读写。

  当用户线程发起一个IO请求操做(本文以读请求操做为例),内核会去查看要读取的数据是否就绪,对于阻塞IO来讲,若是数据没有就绪,则会一直在那等待,直到数据就绪;对于非阻塞IO来讲,若是数据没有就绪,则会返回一个标志信息告知用户线程当前要读的数据没有就绪。当数据就绪以后,便将数据拷贝到用户线程,这样才完成了一个完整的IO读请求操做,也就是说一个完整的IO读请求操做包括两个阶段:

  1)查看数据是否就绪;

  2)进行数据拷贝(内核将数据拷贝到用户线程)。

  那么阻塞(blocking IO)和非阻塞(non-blocking IO)的区别就在于第一个阶段,若是数据没有就绪,在查看数据是否就绪的过程当中是一直等待,仍是直接返回一个标志信息。

  Java中传统的IO都是阻塞IO,好比经过socket来读数据,调用read()方法以后,若是数据没有就绪,当前线程就会一直阻塞在read方法调用那里,直到有数据才返回;而若是是非阻塞IO的话,当数据没有就绪,read()方法应该返回一个标志信息,告知当前线程数据没有就绪,而不是一直在那里等待。

 

.什么是同步IO?什么是异步IO

   咱们先来看一下同步IO和异步IO的定义,在《Unix网络编程》一书中对同步IO和异步IO的定义是这样的:

  A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes.
  An asynchronous I/O operation does not cause the requesting process to be blocked.

  从字面的意思能够看出:

  同步IO即 若是一个线程请求进行IO操做,在IO操做完成以前,该线程会被阻塞;

  而异步IO为 若是一个线程请求进行IO操做,IO操做不会致使请求线程被阻塞。

  事实上,同步IO和异步IO模型是针对用户线程和内核的交互来讲的:

  同步IO当用户发出IO请求操做以后,若是数据没有就绪,须要经过用户线程或者内核不断地去轮询数据是否就绪,当数据就绪时,再将数据从内核拷贝到用户线程;

  而异步IO只有IO请求操做的发出是由用户线程来进行的,IO操做的两个阶段都是由内核自动完成,而后发送通知告知用户线程IO操做已经完成。也就是说在异步IO中,不会对用户线程产生任何阻塞。

  

  这是同步IO和异步IO关键区别所在

  同步IO和异步IO的关键区别反映在数据拷贝阶段是由用户线程完成仍是内核完成。因此说异步IO必需要有操做系统的底层支持。

  注意同步IO和异步IO与阻塞IO和非阻塞IO是不一样的两组概念。

  阻塞IO和非阻塞IO是反映在当用户请求IO操做时,若是数据没有就绪,是用户线程一直等待数据就绪,仍是会收到一个标志信息这一点上面的。也就是说,阻塞IO和非阻塞IO是反映在IO操做的第一个阶段,在查看数据是否就绪时是如何处理的。 

 

5、两种高性能IO设计模式

  在传统的网络服务设计模式中,有两种比较经典的模式:

  一种是 多线程,一种是线程池。

  对于多线程模式,也就说来了client,服务器就会新建一个线程来处理该client的读写事件,以下图所示: 

               

  这种模式虽然处理起来简单方便,可是因为服务器为每一个client的链接都采用一个线程去处理,使得资源占用很是大。所以,当链接数量达到上限时,再有用户请求链接,直接会致使资源瓶颈,严重的可能会直接致使服务器崩溃。

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

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

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

  在Reactor模式中,会先对每一个client注册感兴趣的事件,而后有一个线程专门去轮询每一个client是否有事件发生,当有事件发生时,便顺序处理每一个事件,当全部事件处理完以后,便再转去继续轮询,以下图所示: