node.js深入浅出2-----node.js的c++层

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/strivenoend/article/details/86631320

(一)v8引擎?

V8引擎

首先,学习node.js一定要了解V8引擎,他是一个可以把js直接编译成(处理器可以识别的)机器码的东西。

再详细点,V8是一个

  1. 开源的
  2. 用C++写的
  3. 根据ECMA标准实现JavaScript
  4. 可以把JavaScript编译成处理器可以识别的机器码
  5. 可以独立运行
  6. 也可以嵌入其他C++应用的JavaScript引擎。

(二)Node.js与V8引擎

普通青年使用V8:运行V8, JavaScript -> V8 —compile—> Machine Code

文艺青年则有这样一个大胆的想法:

那些普通的js方法太没意思了,能力优先。如果我可以写一些C++代码,当做Add-on加到V8上,这样V8就有能力识别具有更多的Javascript命令了,就更强大了。比如说file相关的东西,本来js不能做,现在我用c++在底部实现好,然后告诉V8,当用户在js中写道file.open(xxx)的时候,就来用c++执行file open的功能,这样你的js(二b)就是有处理文件能力的js(牛b)了。

原来这个js啊还是很高层的语言啦,你想让他操纵io,他也没那能力啊,因此呀,只能通过c++来搞底层实现啦

文艺青年的想法其实就是我们的Node.js:一个把V8引擎嵌进去的C++应用,这个C++应用实现了超级多的customized新功能,这些功能使得这个应用(Node.js)非常的适合服务器开发。

所以我们讲什么是node.js,,就是一个嵌套了v8的c++应用(c++用于实现底层io功能,v8用于执行js)

服务器开发都需要什么新功能呢 === Node.js实现的新功能都包括哪些方面呢:

嗯,都是用c++写的。。。。。。。。。。。。。。。

(三)Node.js架构

  1. 管理可复用代码
  2. 处理文件
  3. 处理数据库
  4. 互联网通信
  5. 接受request,发送respond
  6. 处理需要一定时间才能完成的工作

第一层是C++ core,就是那些新加的customized功能 (其他讲解中,还会提到比如event loop,libuv等,这些之后说)。

第二层是JS core,这一层用js实现,基于/调用C++ core,让用户可以更好的使用那些C++功能,同时也实现了许多常用的功能。

在node.js源码中,C++ core是在src文件夹内。JS core是在lib文件夹内。由此可见二者的层级关系。

(四)从js到c++经历了什么?

  1. 你写的js代码调用了node.js的JS core (比如 fs相关功能:github.com/nodejs/node…),并且你设定了一个回调函数
  2. JS core部分调用了C++ core (fs.js 调用的其中一个.cc: github.com/nodejs/node…)
  3. C++ core调用libuv
  4. C++ core调用libuv的方法来封装请求对象(异步I/O过程中重要的中间产物,中间指的是从js到os之间),其中包含了异步I/O中最重要的东西之一:回调函数。
  5. libuv把封装好的请求对象发到OS
  6. 发到OS中的线程池(thread pool)等待被执行
  7. 线程池中某一线程将发来的请求对象中包含的I/O操作进行执行,结果存在该请求对象的req->result属性中。然后提交完成状态,也就是类似通知说"我完成了!”,之后把线程归还给线程池
  8. 处于完成状态的请求对象,被观察者(图中的两个小人儿,不同类型的事件有不同的观察者)在事件循环(Event Loop:大while循环,每个循环叫一个tick)中提出来(通过libuv中方法来检查是否有执行完的请求),然后放到队列(Completed Events Queue)中
  9. 事件循环从观察者的队列中取出处于完成状态请求对象
  10. 取出其中包含的I/O操作执行结果以及回调函数,发到V8中执行。到这就达到了调用#1中设定的回调函数的目的。

所谓的特点,就是Node.js是如何解决服务器高性能瓶颈问题的。

a. V8引擎执行的JavaScript是同步的(sync)(stackoverflow.com/questions/2…)且单线程

b. #1-#9 与 #10 是同时在工作的,I/O事件一个一个执行,然后最后发送到V8引擎中一个一个(因为JS是同步的)的执行回调函数

c. 由于b,整个Node.js有了异步I/O的能力

d. 事件驱动(event driven)、非阻塞(non-blocking)I/O的特点也就可以解释了。事件驱动就是指的#7-#10,事件被完成触发了之后各个步骤,直到最后执行回调函数。非阻塞I/O就是整个#1-#10这个过程,我们在V8中执行的JavaScript代码并不会因为事件的执行而停止,#1-#9和#10同时工作,一个执行I/O事件,一个得到通知执行回调函数。

e. 从d的解释中,可以更好的理解上一篇文章中最后那段说Node.js是单线程/多线程。

下次写事件(Event)和事件发射器(Event Emitter)相关的东西。欢迎大家交流,指正~

(五)node.js和java的多线程?并发访问量?

单线程

在Java、PHP或者.net等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约2MB内存。也就是说,理论上,一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。要让Web应用程序支持更多的用户,就需要增加服务器的数量,而Web应用程序的硬件成本当然就上升了。

Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的。使用Node.js,一个8GB内存的服务器,可以同时处理超过4万用户的连接。

另外,带线程的带来的好处,还有操作系统完全不再有线程创建、销毁的时间开销。

坏处,就是一个用户造成了线程的崩溃,整个服务都崩溃了,其他人也崩溃了。

clip_image002 clip_image004

多线程、单线程的一个对比。

也就是说,单线程也能造成宏观上的“并发”。

非阻塞I/O non-blocking I/O-------线程执行线程的,io执行io的,两者并行

例如,当在访问数据库取得数据的时候,需要一段时间。在传统的单线程处理机制中,在执行了访问数据库代码之后,整个线程都将暂停下来,等待数据库返回结果,才能执行后面的代码。也就是说,I/O阻塞了代码的执行,极大地降低了程序的执行效率。

由于Node.js中采用了非阻塞型I/O机制,因此在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的执行效率。

当某个I/O执行完毕时,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理。

阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程的CPU核心利用率永远是100%所以,这是一种特别有哲理的解决方案:与其人多,但是好多人闲着;还不如一个人玩命,往死里干活儿。

(六)node.js适合做?

少用cpu,多用io的应用

当应用程序需要处理大量并发的I/O,而在向客户端发出响应之前,应用程序内部并不需要进行非常复杂的处理的时候,Node.js非常适合。Node.js也非常适合与web socket配合,开发长连接的实时交互应用程序。

(七)对node.js单线程的误解?node.js工作时真的只有一个线程吗?

为什么单线程却能够支持高并发?
(1)前提:I/O密集型任务
(2)单线程的解释:主线程一个,底层工作线程多个。
(3)事件机制的底层依赖库:libuv、libeio、libev

libuv:开发node过程中需要跨平台,首选为Linux使用libev(底层    为epoll),备选Windows使用IOCP实现,用于抽象libev和IOCP的高性能网络库。
非阻塞TCP、非阻塞命名管道、UDP、异步DNS
异步文件系统、路径查找、ANSI转义、文件系统事件
子进程生成、线程池调度、进程间IPC与套接字共享
高分辨率时间、定时器
epoll和IOCP的区别:
epoll用于Linux系统,IOCP用于Windows系统;
epoll是同步非阻塞模型:当事件资源满足时发出可处理通知消息(主线程需要自己去处理);IOCP是异步非阻塞模型,当事件完成时发出通知消息(工作线程帮主线程处理完了)
(4)nodejs运行机制:

a、V8引擎解析JavaScript脚本
b、解析后的代码,调用Node API
c、libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎
d、V8引擎再将结果返回给用户、


(八)单线程的利弊

  • 单线程的好处:
    (1)多线程占用内存高
    (2)多线程间切换使得CPU开销大
    (3)多线程由内存同步开销
    (4)编写单线程程序简单
    (5)线程安全

  • 单线程的劣势:
    (1)CPU密集型任务占用CPU时间长
    (2)无法利用CPU的多核
    (3)单线程抛出异常使得程序停止

(九)node.js真的是单线程吗?

  • è¿éåå¾çæè¿°

  • Node.js的单线程并不是真正的单线程,只是开启了单个线程进行业务处理(cpu的运算),同时开启了其他线程(io线程)专门处理I/O。当一个指令到达主线程,主线程发现有I/O之后,直接把这个事件传给I/O线程,不会等待I/O结束后,再去处理下面的业务,而是拿到一个状态后立即往下走,这就是“单线程”、“异步I/O”。 
     

(十)node.js如何解决的高并发?

如何解决高并发?

node使用异步IO和事件驱动(回调函数)来解决这个问题。

一般来说,高并发解决方案会提供多线程模型,为每个业务逻辑提供一个线程,通过系统线程切换来来弥补同步I/O调用的时间开销。像apache,是一个请求一个线程。

猜你喜欢

转载自blog.csdn.net/strivenoend/article/details/86631320