Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node之waht、why #22

Open
SumyHu opened this issue Jan 22, 2019 · 0 comments
Open

Node之waht、why #22

SumyHu opened this issue Jan 22, 2019 · 0 comments

Comments

@SumyHu
Copy link
Contributor

SumyHu commented Jan 22, 2019

Node是什么?

从官网中,我们可以看到对Node最精简、准确的描述:
image
看完官网对Node的描述后,让我们带着以下几个问题往下看这篇文章:

  1. Node为什么要基于Chrome的V8殷勤?
  2. 为什么说Node是JavaScript的运行环境?
  3. 什么是事件驱动?
  4. 什么是非阻塞式I/O?
  5. 为什么使用了事件驱动、非阻塞式I/O模型可以达到轻量又高效的效果?

Node的来源

image
从上文中,我们可以获取以下几个关键点:

  1. 对于高性能,异步IO、事件驱动是基本原则
  2. 因为JavaScript是单线程执行,根本不能进行同步IO操作,所以,JavaScript的这一“缺陷”导致了它只能使用异步IO
  3. V8是开源的JavaScript引擎
  4. 基于JavaScript语言和V8引擎的开源web服务器项目,命名为Node.js
  5. Node第一次把JavaScript带入到后端服务器开发

从上述信息中,我们多次提到同步和异步、阻塞和非阻塞,那到底什么是同步和异步、阻塞和非阻塞呢?

同步和异步,阻塞和非阻塞

同步和异步

同步

  • 如果在函数A返回的时候,调用者就能够得到预期结果(即拿到了预期的返回值或者看到了预期的效果),那么这个函数就是同步的。
  • 所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。就是一旦调用返回,就得到返回值了。
  • 换句话说,就是由调用者主动等待这个调用的结果。调用者对消息结果的获取是主动发起的。

举例:

  • Math.sqrt(2);
  • console.log(‘Hi’);
  • $.ajax({ url: url, type: ‘POST’, async: false, success: function(data) {} });
  • 你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说:“你稍等,我查一下”,然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。

异步

  • 如果在函数A返回的时候,调用者还不能够得到预期结果,而是需要在将来通过一定的手段得到,那么这个函数就是异步的。
  • 所谓异步,就是在发出一个调用后,这个调用就直接返回了,所以没有返回结果
  • 换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,**被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。**调用者对消息结果的获取是被动通知的。

举例:

  • Fs.readFile(‘foo.txt’, ‘utf8’, function(err, data) {
    console.log(data);
    });
  • 你打电话问书店老板有没有《分布式系统》这本书,如果是异步通信机制,书店老板直接告诉你:“我查一下,查好了打电话给你”,然后直接挂电话了(不返回结果)。然后查好了,他主动打电话给你。在这里,老板通过“回电”这种方式来回调。

阻塞和非阻塞

阻塞

  • 阻塞调用是指调用结果返回之前,当前线程会被挂起。挂起状态意味着当前线程什么都不干,一直等待数据返回的状态,直到数据返回后,当前线程才会继续往下处理其他任务。

举例:

  • 你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果。

非阻塞

  • 非阻塞调用是指在不能立刻得到结果之前,该调用程序仍然是运行状态,该调用不会阻塞当前线程,当前程序可以继续处理其他任务。

举例:

  • 如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。

通过前端代码对同步和异步、阻塞和非阻塞的举例说明

同步阻塞

image
在获取接口调回的结果前线程被阻塞,只能等。

同步非阻塞

image
假设每次调用接口,都会立刻把值返回,但返回的值不一定是调用者所希望,此时,调用者在每次接口调用之间可以进行别的事情,线程并没有被阻塞。

异步阻塞

image
在调用的接口返回数据前,什么都不做,直到调用的接口有数据返回才继续往下执行。

异步非阻塞

image
不管接口有没有数据返回,线程都正常工作,继续往下执行代码。

同步IO和异步IO

什么是IO?

  • io input、output 输入输出,电脑的输入输出,例如音频录音表示声音输入、听音乐是声音的输出
  • 网络上的传输全部是在传字符串,i/o在服务器上可以理解为读写操作。

同步IO

同步IO的特点:

  • 同步IO指的是用户进程触发I/O操作并等待或者轮询的去查看I/O操作是否就绪。
  • 同步IO的执行者是IO操作的发起者。
  • 同步IO需要发起者进行内核态到用户态的数据拷贝过程,所以这里必须有个阻塞。

异步IO

异步IO的特点:

  • 异步IO是指用户进程触发I/O操作以后就立即返回,继续开始做自己的事情,而当I/O操作已经完成的时候会得到I/O完成的通知。
  • 异步I/O的执行者是内核线程,内核线程将数据从内核态拷贝到用户态,所以这里没有阻塞。

如何区分是同步IO还是异步IO呢?

“执行IO操作”是否阻塞

当请求被阻塞,就是同步IO,否则就是异步IO

阻塞IO和非阻塞IO

如何区分是阻塞IO还是非阻塞IO呢?

发起IO操作是否阻塞?

如果阻塞知道完成,就是阻塞IO,否则就是非阻塞IO

讨论几个IO模型

让我们来讨论几个比较有代表性的IO模型,以加深我们对同步IO和异步IO、阻塞IO和非阻塞IO的了解。
image

阻塞式I/O模型

image

非阻塞式I/O模型

image

I/O复用模型

image

信号驱动式I/O模型

image

异步I/O模型

image

讲完什么是同步和异步、阻塞和非阻塞,什么是同步IO和异步IO、阻塞IO和非阻塞IO,下面我们再来讲讲“因为JavaScript是单线程执行,根本不能进行同步操作,所以,JavaScript的这一‘缺陷‘导致了它只能使用异步IO”这句话是什么意思。

JavaScript的特性

因为JavaScript是单线程执行,根本不能进行同步操作,所以,JavaScript的这一“缺陷”导致了它只能使用异步IO

这句话的意思是这样理解的:

  1. JavaScript的确是单线程的
  2. 异步是浏览器的JavaScript引擎做的工作

我们常说“JavaScript是单线程的”。所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。不妨叫它主线程。JS引擎中负责解释和执行JavaScript代码的线程只有一个,说明代码只能按照执行顺序一行一行执行,遇到耗时代码就会阻塞住(不能像其他语言一样开一个线程来执行耗时操作)
然而浏览器是事件驱动的,很多操作是异步的,浏览器有多个线程来做此工作。例如:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(例如在Node.js中)等等。这些线程可能存在于JS引擎之内,也可能存在于JS引擎之外,在此我们不做区分。不妨叫它们工作线程。js 中的异步代码如 AJAX 完成请求、 setTimeout() 定时器到时间后,浏览器会把这些需要执行的异步操作放到自己的消息队列中,并轮循这个队列,在浏览器空闲时处理事件。

那什么是事件驱动呢?它是怎么实现异步的呢?

事件驱动

image
image
image
image
image
image
image

Node官网中对Node有过这样一句描述:“Node.js使用了一个事件驱动、非阻塞式I/O的模型,使其轻量又高效”。我们来看一下Node的工作原理。

node工作原理

主线程

  1. 执行node的代码,把代码放入队列
  2. 事件循环程序(主线程)循环读取队列里面的代码
  3. 若读取的代码为同步代码,则直接执行了
  4. 若读取的代码为执行异步代码,则:
  1. 异步非io setTimeout() setInterval() 判断是否可执行,如果可以执行就把callback扔回到队列,不可以执行就跳过(不从队列中删除)。
  2. 异步io 文件操作 会从线程池当中去取一条线程,帮助主线程去执行,当子线程执行完毕后,会将callback扔回到队列。
  1. 主线程会一直轮询,队列中没有代码了,主线程就会退出。

子线程

  1. 在线程池里休息
  2. 异步io的操作来了,执行异步io操作。
  3. 子线程会在异步io代码执行完成的时候,将callback函数扔回给队列
  4. 异步io执行完后子线程会回到线程池去休息。

Node工作流程如下图所示:
image

Node是基于Chrome V8引擎的

Node为什么要基于Chrome V8引擎呢?
image
所以Node.js是一个基于Chrome V8引擎的JavaScript的运行环境。

所以,我们可以通过Node做什么呢?

Node能做什么?

  • Node.js是一个能够在服务器端运行JavaScript的开放源代码、跨平台JavaScript运行环境。它是一个运行环境,并不是其他的什么比如软件库,简而言之,和C#所需要的编译环境一样,Node.js就是JavaScript的编译环境。因此,可以让前端语言JavaScript在写完之后交给Node.js进行编译和解释。
  • 在Node.js出现之前,JavaScript通常作为客户端程序设计语言使用,以JavaScript写出的程序常在用户的浏览器上运行。Node.js的出现使JavaScript也能用于服务端编程。Node.js含有一系列内置模块,使得程序可以脱离Apache HTTP Server或IIS,作为独立服务器运行。

Node解决了什么问题?

传统服务存在如下问题:
image
传统服务器处理请求的流程如下图所示:
image

Node解决如下问题:
image
Node.js的应用是通过javascript开发的,然后直接在Google的变态V8引擎上跑。用了Node.js,你就不用担心用户端的请求会在服务器里跑了一段能够造成阻塞的代码了。因为javascript本身就是事件驱动的脚本语言。
Node处理请求的流程如下图所示:
image

使用Node的优劣势

优势

  • 采用事件驱动、异步编程,为网络服务而设计。其实Javascript的匿名函数和闭包特性非常适合事件驱动、异步编程。而且JavaScript也简单易学,很多前端设计人员可以很快上手做后端设计。
  • Node.js非阻塞模式的IO处理给Node.js带来在相对低系统资源耗用下的高性能与出众的负载能力,非常适合用作依赖其它IO资源的中间层服务。
  • Node.js轻量高效,可以认为是数据密集型分布式部署环境下的实时应用系统的完美解决方案。Node非常适合如下情况:在响应客户端之前,您预计可能有很高的流量,但所需的服务器端逻辑和处理不一定很多。

劣势

  • 可靠性低。
  • 单进程,单线程,只支持单核CPU,不能充分的利用多核CPU服务器。一旦这个进程崩掉,那么整个web服务就崩掉了。

当然对于这些缺点也有很多解决办法:
开启多个进程,每个进程绑定不同的端口,用反向代理服务器如 Nginx 做负载均衡,好处是我们可以借助强大的 Nginx 做一些过滤检查之类的操作,同时能够实现比较好的均衡策略,但坏处也是显而易见——我们引入了一个间接层。
多进程绑定在同一个端口侦听。在Node.js中,提供了进程间发送“文件句柄” 的功能。
一个进程负责监听、接收连接,然后把接收到的连接平均发送到子进程中去处理。

Node的使用场景

  • IO密集而非计算密集的情景
  • 高并发微数据

附录

参考资料如下:
https://www.cnblogs.com/euphie/p/6376508.html
https://segmentfault.com/a/1190000004322358
https://www.zhihu.com/question/19732473
https://segmentfault.com/a/1190000014840597
https://zhuanlan.zhihu.com/p/36344554
https://blog.csdn.net/u013217071/article/details/78043081
https://zhuanlan.zhihu.com/p/30743785
https://juejin.im/post/59e85eebf265da430d571f89?tdsourcetag=s_pcqq_aiomsg

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant