Nginx 阻塞与非阻塞,同步与异步_客户端

 

同步与异步


同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)。所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由*调用者*主动等待这个*调用*的结果。而异步则是相反,*调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在*调用*发出后,*被调用者*通过状态、通知来通知调用者,或通过回调函数处理这个调用。

同步和异步是调用的方式而言,也就是编码的时候写业务逻辑这样一个角度。典型的异步编程模型比如Node.js

举个通俗的例子:你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,"我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过"回电"这种方式来回调。

 

阻塞与非阻塞


阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

阻塞和非阻塞主要指操作系统或底层的C库提供的方法或者系统调用,也就是调用该方法的时候可能会导致进程进入sleep状态。

为什么会进入sleep状态呢 ,因为当前的条件不满足的情况下操作系统主动的将进程切换为另外一个进程使用当前CPU。这样就是一个阻塞方法。

非阻塞就是调用该方法,永远不会因为时间片未用完的时候将进程主动切换掉。

还是上面的例子,你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己"挂起",直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。

 

 

如果还是不清楚看下面


同步和异步

同步和异步强调是通知的方式。

 

同步 :同步是当函数调用发出之后,一直等待调用的结果。

举个栗子🌰:

小杰想看书了,就来到图书馆借书,到柜台跟管理员说:我想借一本《平凡的世界》。管理员说:你等着哈,我给你找。然后小杰就一直等着,直到管理员给她找书的结果。然后她拿着书才去继续做接下来要做的事。(小杰期望当时立即把找书的结果给他)

解释:小杰同步等待,直到得到管理员返回找书的结果,这个过程就是同步调用,就像我们调用一个函数,如果函数处理时间过长,卡住了,我们仍然要等着函数结束,获取到函数的返回结果。

 

异步:异步是当一个调用结束之后没有得到返回结果,补偿通知的方式获取结果。

举个栗子🌰:

小杰又想看书了,就跟管理员打电话说:我想借一本《围城》。管理员说:我这就给你找,一会儿再打给你。(小杰不期望管理员当时在电话里立即把找书的结果给她)

解释:小杰打电话的时候,管理员把结果返回给小杰的方式,不是在打电话的时候就返回的。而是管理员可能找书花费了1个小时(也可能更长时间),1个小时之后把结果通知给小杰的。

 

阻塞与非阻塞

阻塞非阻塞强调的是在调用发生之后进程是否挂起。

 

阻塞

函数调用开始之后,一直等待函数返回,什么也不做。(挂起)

举个栗子🌰:

(同步阻塞)小杰要借书,来到图书馆,让图书管理员帮忙找书,图书管理员在找书的过程中,小杰什么也不做,一直在等待管理员找书的结果。

(异步阻塞)小杰通过打电话给图书管理员,打完电话之什么也不做,一直在等待管理员找书的结果。

解释:不管是同步还是异步,在等待调用结果的时候,都没有去做其他的事情。(进程挂起,有调用结果了重新唤醒进程)

 

非阻塞

举个栗子🌰:

(同步非阻塞)小杰借书的时候,来到图书馆,图书管理员在找书的过程中,一边刷手机,一直在等待管理员找书的结果。

(异步非阻塞)小杰借书的时候,打电话给图书管理员,打完电话之后,就去洗衣服去了,一边等待管理员找书结果的电话,一边洗衣服。

解释:同理,不管是同步还是异步,在等待调用结果的时候,转而做其他的事情。(进程没有挂起)

同步和异步、阻塞和非阻塞在真实场景里面也会根据实际情况进行选择。当然异步非阻塞用的是最多的。

Nginx在处理请求的时候,采用的是异步非阻塞原理,监听每个网络请求连接IO的是否有可读或者可写的事件发生。一个负责监听的守护进程可以同时响应多个网络请求连接。异步非阻塞是IO复用的基础。

 

最后再来看看Nginx如何处理请求


  异步方式是和多进程方式及多线程方式完全不同的一种处理客户端请求的方式。

  网络通信中的同步机制和异步机制是描述通信模块的概念。同步机制,是指发送方发送请求后,需要等待接收到接收方发回的响应后,才接着发送下一个请求;异步机制,和同步机制正好相反,在异步机制中,发送方发出一个请求后,不等待接收方响应这个请求,就继续发送下个请求。在同步机制中,所有的请求在服务器端得到同步,发送方和接收方对请求的处理步调是一致的;在异步机制中,所有来着发送方的请求形成一个队列,接收方处理完成后通知发送方。

   阻塞和非阻塞用来描述进程处理调用的方式,在网络通信中,主要指网络套接字Socket的阻塞和非阻塞方式,而Socket的实质也是IO操作Socket的阻塞调用方式为,调用结果返回之前,当前线程从运行状态被挂起,一直等到调用结果返回之后,才进行就绪状态,获取CPU后继续执行;Socket的非阻塞调用方式和阻塞方式调用方式正好相反,在非阻塞方式中,如果调用结果不能马上返回,当前线程也不会被挂起,而是立即返回执行下一个调用。

   Nginx服务器的一个显著优势是能够同时处理大量并发请求。它结合多进程机制和异步机制对外提供服务,异步机制使用的是异步非阻塞方式

   Nginx服务器启动后,可以产生一个主进程(master process)和多个工作进程(worker processes),其中可以在配置文件中指定产生的工作进程数量。Nginx服务器的所有工作进程都用于接收和处理客户端的请求。这类似于Apache使用的改进的多进程机制,预先生成多个工作进程,等待处理客户端请求。

  每个工作进程使用了异步非阻塞方式,可以处理多个客户端请。当某个工作进程接收到客户端的请求以后,调用IO进行处理,如果不能立即得到结果,就去处理其他的请求;而客户端在此期间业务无需等待响应,可以去处理其他的事情;当IO调用返回结果时,就会通知此工作进程;该进程的到通知,暂时挂起当前处理的事务,去响应客户端请求。

  客户端请求数量增长、网络负载繁重时,Nginx服务器使用多进程机制能够保证不增长对系统资源的压力;同时使用异步非阻塞方式减少了工作进程在I/O调用上的阻塞延迟,保证了不降低对请求的处理能力。