异步式(Asynchronous)与同步式Synchronous)

  同步异步通常用来形容一次方法调用。

  • 同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。
  • 异步方法调用更像一个消息传递,一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。而,异步方法通常会在另外一个线程中,“真实”地执行着。整个过程,不会阻碍调用者的工作。
  • 图示例

    理解IO

         IO(Input/Output)通常是指计算机线程进行慈磁盘读写或者网络通信时的一种行为。

    同步式(Synchronous)IO和异步式(Asynchronous )IO

     

          同步式: 当计算机调度线程进行I/O操作命令后,由于文件的读写或者网络通信需要较长的操作时间,操作系统为了充分利用cpu,此时会暂停到当前的I/O线程对CPU的控制(故又称同步式为阻塞式I/O),把cup资源然给其他的线程资源,当I/O线程完成了操作时,此时操作系统会恢复此时的I/O线程,从而当前I/O线程重新获得了cup的的控制权,继续完成其他操作。

         NodeJs让很多前端开发者利用JS开发服务器变得异常的简单,而异步式I/O则是NodeJs的一大特点。

          异步式 :异步式IO又称非阻塞式I/O,异步式与同步式不同的是,当线程进行IO操作时,操作系统并不是暂停当前的线程操作,而是执行完I/O指令后,操作系统继续让当前线程执行下一条指令,当I/O操作完成后,会通过事件(event)通知I/O线程,而线程在接收到通知后,会处理响应事件。

         简单的说,同步式是让通过多个线程完成多个任务,而异步式则是通过一个线程完成多个任务,遇到I/O操作时,依然让线程继续执行其他指令,只是在I/O完成后通知线程调度响应事件即可。

    图解:


所谓同步,简单的说,A告诉B去做某件事情,然后就一直等待,直到B做完后返回给A,A才继续做其它的事情;
所谓异步,相反的,A告诉B做某件事情,然后就去干其它的事情了,B做完后再通知A。

无论是同步还是异步,其实都是指两个对象之间的交互。所以,判断什么是同步还是异步,首先要先明确指的是哪两个对象之间的关系。
举个例子:

  1. socket.write(request);  
  2. response = socket.read();  

这是一段常见的伪代码,用于Client向Server发送请求。在这里,可以说socket.write是一个同步IO,因为调用write操作以后,内核会将要写的数据放入到网卡的缓冲区中,然后再返回,所以,这里同步的两个对象分别是应用程序和内核;也可以说这段代码是一个同步消息机制,因为client将request发送给server后,一直等待直到server将response返回,这里同步的两个对象分别是client和server。

之前的那篇blog专门论述同步IO和异步IO,它指的是应用程序和操作系统内核间的关系。这里就不多谈了。这里谈谈Mina。Mina是一个非常流行的网络程序的框架,它提供的是异步的API(It provides an abstract • event-driven • asynchronous API)。
比如,如果client想要创建一个到server的连接,用mina可以这样写:

  1.  NioSocketConnector connector = new NioSocketConnector();  
  2. // 初始化connector...  
  3. //..........  
  4. connector.connect(address);  

看上去好像和一般的写法没什么两样。但是,这里的connector.connect()方法是一个异步的调用,意思是程序告诉mina要去连接address,mina返回说它会做这件事,但它可能还没有做完。所以,即便“connector.connect(address);”这行代码结束了,也并不意味着连接成功了(mina这时候可能还正在创建连接的过程中)。完整的写法应该是:

  1. ConnectFuture connFuture = connector.connect(address);  
  2. connFuture.addListener(new ConnectListener());  
  3.         private class ConnectListener implements IoFutureListener<ConnectFuture>{  
  4.               
  5.             public void operationComplete(ConnectFuture future) {  
  6.                   
  7.                 if (future.isConnected()) {  
  8.                     //get session  
  9.                     IoSession session = future.getSession();  
  10.                       
  11.                     session.write(...);  
  12.                       
  13.                 } else {  
  14.                       
  15.                     logger.error("can not create the connection .");  
  16.                 }  
  17.             }  
  18.         }  
  19.     }  
  20. }  

这里面最重要的一个类是ConnectListener,它实现了IoFutureListener<ConnectFuture>这个接口。这个类其实只有一个函数 – operationComplete,这是一个回调函数,它告诉mina一旦connect完成以后,就调用这个函数。我们这里的回调函数,首先判断一下连接是否成功,如果成功,那么就向这个链接中写入数据(session.write)。

回调函数在异步机制中扮演着非常重要的角色。因为在同步机制中,调用者会等到结果返回然后自己执行接下来的操作,比如,上面这段代码如果写成同步的,大概是这个样子:

  1. boolean status = connector.connect(address);  
  2. if(status) {  
  3.     session.write(...);  
  4. else {  
  5.     logger.error("can not create the connection .");  
  6. }  

但是在异步机制中,就只能将connect后面的代码做成回调函数,注册到mina中。这样,当mina完成工作后它才知道接下去该干什么。

值得一提的是,虽然Mina号称是Asynchronous API,但它也提供了同步的方法。比如,上面这段代码,如果用Mina的同步机制是这样写的:

  1. ConnectFuture future = connector.connect(address);  
  2. future.awaitUninterruptibly();  
  3. IoSession session = future.getSession();  
  4.         // Send the first ping message  
  5.         session.write(....);  
重点在于“future.awaitUninterruptibly();”这行代码,它会将程序阻塞住,直到连接创建好,所以,当这行代码结束后,就可以直接获取session并执行write操作。

同步~异步~阻塞~非阻塞

    同步(Synchronous)和异步(Asynchronous)的概念本来来自通信领域:首先是通信的同步,主要是指客户端在发送请求后,必须得在服务端有回应后才发送下一个请求,所以这个时候的所有请求将会在服务端得到同步;其次是通信的异步,指客户端在发送请求后,不必等待服务端的回应就可以发送下一个请求,这样对于所有的请求动作来说将会在服务端得到异步,这条请求的链路就像是一个请求队列,所有的动作在这里不会得到同步的。


    阻塞(Blocking)和非阻塞(Non-blocking)主要是指某个程序模块、进程是否占用了系统的某种资源(各种硬件资源和软件资源,甚至包括时间等等)而影响其它程序模块、进程无法运行或者处理它的任务。如果影响了,就是阻塞;如果没有影响,就是非阻塞。

    很多人会把“同步/异步”和“阻塞/非阻塞”的概念搞混淆,总认为同步就是阻塞,异步就是非阻塞。从上面的描述可以看出,其实“同步/异步”和“阻塞/非阻塞”之间是没有任何关系的。

   

 同步调用~异步调用~阻塞调用~非阻塞调用

    在实际中,我们说“同步和异步”,其实往往指的是函数调用的“同步和异步”,也就是“同步调用和异步调用”。所谓同步调用,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。异步调用的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果,但调用者会立即从被调用者返回。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。


    阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

    这个时候又有很多人会把“同步调用和异步调用”和“阻塞调用和非阻塞调用”搞混淆,把同步调用等同于阻塞调用,把异步调用等同于非阻塞调用,其实这是不对的。


    对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。而对于阻塞调用来说,当前线程会立即挂起,硬要等到要做的事情完成才会退出。

    对于异步调用来说,它往往只是Assign一个Task给被调用部件,被调用部件返回的结果是接不接受调用者的Task请求(如果太忙,或者任务队列满等原因会导致不接受请求),如果它接受你的请求,等到它做完后会想办法告诉调用者。而对于非阻塞调用来说,就是在调用的时候,如果被调用者能完成,就直接完成并告诉你完成了,如果它完不成就会告诉被调用者它无法完成,并告诉调用者它完不成的原因(当然,有些情况会省略这一步,一种情况是调用者不在意是什么原因导致执行部件无法完成;还有一种情况是只有一种原因导致执行部件无法完成,所以不说调用者也知道)。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值