当前位置: 首页 > 编程日记 > 正文

关于node.js的误会

昨天写了篇博客,介绍了一下我对node.js的第一次亲密接触后的感受,以为node.js很小众,出乎我意料很多人感兴趣,并且对博客中的细节问题做了评论,最多的是围绕node.js的异步与单线程展开的,当然还有很多关于node.js究竟是不是语言?不是的话又是什么。。。之类的问题,其实刚接触node.js,了解的并不是很深入,越是回复大家问题,心里越是没底,决定认真研究一下,经人指点看了一下《Node.js开发指南》发现大部分问题都有了答案,权当一个读书笔记把问题答案分享出来,希望可以帮到一些和我一样才接触node.js的小菜

关于单线程一个由来已久的误会

在上篇博客中提到我们使用node.js写的JavaScript代码是单线程运行的,让很多同学很疑惑,单线程怎么实现异步操作,单线程谁去响应事件。。。在html5 Web Workers中我也有提到过客户端的JavaScript也是单线程运行的,大家明显没有这么大反应,还是普遍能接受的。可单线程的客户端JavaScript也能响应DOM事件,还有大家都很熟悉的ajax操作,回调函数也是异步的,既然客户端JavaScript是单线程执行的,回调函数是谁调用的呢?答案很简单,JavaScript的宿主环境——浏览器,也就是说虽然JavaScript是单线程执行的,但浏览器是多线程的,负责调度管理JavaScript代码,让它们在恰当的时机执行。

所以我们所说的node.js单线程,是指node.js并没有给我们创建一个线程的能力,所有我们自己写的代码都是单线程执行的,在同一时间内,只能执行我们写的一句代码。但宿主环境node.js并不是单线程的,它会维护一个执行队列,循环检测,调度JavaScript线程来执行。因此单线程执行和并发操作并不冲突。

阻塞与线程

什么叫阻塞(block)?线程在执行中如果遇到I/O操作(磁盘读写、网络通信等)通常需要耗费较长的时间,这时候操作系统会剥夺线程对CPU的控制权,使其暂停,并把资源让给其它的工作线程,这种线程调度方式成为阻塞。当I/O操作完毕的时候操作系统将这个线程的阻塞状态解除,恢复其对CPU的控制权,令其继续执行,这种I/O模式就是同步I/O或成为阻塞I/O。

响应的异步I/O或非阻塞I/O则针对所有的I/O操作采取不阻塞的策略,当线程遇到I/O操作时不会以阻塞的方式等待I/O操作结束,而只是将I/O请求发送给操作系统,继续执行后续语句。当操作系统完成I/O操作时以事件的形式通知执行I/O操作的线程,线程会在特定时间处理这个事件。为了处理异步I/O必须有事件循环,不断检查有没有未处理的事件,依次予以处理。

在阻塞模式下,一个线程只能处理一个任务,要想提高吞吐量必须通过多线程。而在非阻塞模式下一个线程永远在执行计算操作,这个线程所使用的CPU核心利用率永远是100%,I/O以事件的方式通知。在阻塞模式下多线程往往能够提高系统吞吐量,因为一个线程阻塞时还有其他线程在工作,多线程何以让CPU资源不被阻塞的线程浪费。而在非阻塞模式下,线程不会被I/O阻塞,永远在利用CPU。异步I/O减少了多线程中创建线程、分配内存、列入调度、切换线程、内存换页、CPU缓存等方面的开销。

事件循环机制

上面提到了几次事件循环机制,那么这个听起来貌似很高端的东东究竟是什么呢?所谓事件循环是指node.js会把所有的异步操作使用事件机制解决,有个线程在不断地循环检测事件队列。node.js中所有的逻辑都是事件的回调函数,所以node.js始终在事件循环中,程序入口就是事件循环第一个事件的回调函数。事件的回调函数中可能会发出I/O请求或直接发射( emit)事件,执行完毕后返回事件循环。事件循环会检查事件队列中有没有未处理的事件,直到程序结束。node.js的事件循环对开发者不可见,由libev库实现,libev不断检查是否有活动的、可供检测的事件监听器,直到检查不到时才退出事件循环,程序结束。

node.js是什么?和JavaScript有什么关系?

关于node.js究竟是什么,大家的问题在于

  1. node.js是不是一门语言?
  2. node.js是不是一个JavaScript库函数?
  3. node.js是不是一个JavaScript框架?

很遗憾,这三个问题的答案都是NO,看看官方对自己的描述

Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

官方很明确地说node.js是一个platform,也就是一个做xxx的平台。node.js是一个可以在服务器端运行JavaScript的平台,其实这句话华也不准确,按照《JavaScript权威指南》《JavaScript高级程序设计》等书中的定义,JavaScript是由两部分组成

  1. core JavaScript
  2. client JavaScript(DOM、BOM)

而只有core JavaScript可以在node.js上运行,所以node.js借用了JavaScript的语法,但并不能用来处理浏览器对象(BOM)及文档对象(DOM),所以node.js并不是设计为在服务器端运行解析html文档的(当然有module可以做此事),所以“在服务器端运行的JavaScript”在一定程度上误导了初学者。

同时node.js并不仅仅运行core JavaScript,node.js中还有文件系统、模块包、操作系统API、网络通信、二进制类型处理等core JavaScript不具备的功能。

node.js是在执行JavaScript语句吗

从字面意思上是的,因为我们在使用node.js开发的时候写的确实是JavaScript语句,而且node.js利用Google的V8 Javascript 引擎来解析JavaScript语句,但系统真正调用执行的代码是用C++写的,我们做的只是用JavaScript语句来调用这些底层API,所以不用担心其执行效率过低问题

异步I/O与事件驱动

毫不夸张的说node.js最大的特定就是采用异步I/O和事件驱动架构,对于高并发解决方案传统架构师多线程模型,为每个业务逻辑童工一个线程,通过系统线程切换来来弥补同步I/O调用的时间开销。node.js使用的是单线程模型,对所有I/O都采用异步式的请求方式,避免频繁的上下文切换,在node.js执行的时候维护着一个事件队列,程序在执行时进入事件循环等待下一个事件到来,每个异步I/O请求完成后都会被推送到事件队列中的等待执行。

对于一个简单的数据库访问操作,传统方式是这样实现的

 res = db.query('SELECT * from some_table');res.output();

代码执行到第一行的时候线程会阻塞,等待query返回结果,然后继续处理。由于数据库查询、磁盘读写、网络通信等原因阻塞时间会非常大(相对于CPU始终频率)。对于高并发的访问,一方面线程长期阻塞等待,另一方面为了应付新情求而不断添加新线程,会浪费大量系统资源,同时线程的增加也会也会占用大量的CPU时间来处理内存上下文切换。看看node.js怎么处理

db.query('SELECT * from some_table', function(res) { 
res.output(); });

在代码中熟悉Javascript的同学一眼就可以看明白query的第二个参数是一个回调函数,进程执行到db.query的时候不会等待结果返回,而是直接继续执行下面的语句,直到进入事件循环。当数据库执行结果返回的时候会将事件发送到事件队列,等到线程进入事件循环后才会调用之前的回调函数。

node.js的异步机制是基于事件的,所有的I/O、网络通信、数据库查询都以非阻塞的方式执行,返回结果由事件循环来处理。node.js在同一时刻只会处理一个事件,完成后立即进入事件循环检查后面事件。这样CPU和内存在同一时间集中处理一件事,同时尽量让耗时的I/O等操作并行执行。

node.js架构

node.js用异步式I/O和事件驱动代替多线程提升性能,除了使用高效的V8作为JavaScript引擎外还使用了高效的libev和libeio库支持事件驱动和异步I/O。

node.js作者在libeio和libev的基础上抽象出了libuv层,对于POSIX(Portable Operating System Interface 是一套操作系统API规范,遵循的有Unix、Linux、Mac OS X等)操作系统libuv通过封装libev和libio来利用epoll或kqueue。而在Windows下libuv使用了IOCP(Input/Output Completion Port,输入输出完?端)机制 在不同平台下实现高性能。

了解了这个就不要再以为node.js是利用JavaScript来操作系统了

为什么要使用node.js

其实这个问题可以归结为node.js有什么特长,除了语法上让熟悉JavaScript的人很舒服。相对于Javascript为客户端而生,node.js为网络而生,一切都以http为主,其内建HTTP服务器支持,使用node.js可以轻易地搭建一个网站和服务器组合,而不用想使用PHP还需要额外的Apache服务器,通过特有模块或CGI调用才能将PHP脚本结果返回给用户。

node.js还可以部署到非网络应用环境下,因为其可以调用C/C++代码,充分利用现有函数库,在性能上有很大优越性。

在这些场景下使用node.js是非常合适的

  • web socket服务器
  • TCP/UDP套接字应用程序
  • 复杂逻辑的web应用
  • 命令行工具
  • 客户端Javascript编译器

参考及最后

博客中基本理论知识都来源于《Node.js开发指南》,甚至很多篇幅都是直接使用原话,没有抄袭据为己有的意思,只是作者说的太明白了,希望对初入node.js的朋友有帮助,当然如果感兴趣可以直接购买原书。

希望唠唠叨叨这么多,能够对对之前博客持有疑问的博友有所帮助,最后在唠叨一句,单线程执行是指我们写的JavaScript语句在同一时刻只能执行一句,而不是node.js是单线程,其实我们的异步I/O及事件循环都是另外线程在做。

当然对于一些CPU密集的操作在node.js里面也有process.nextTick()这样的解决方案或者直接使用C++处理,研究明白了和大家分享,也有人不满意node.js的单线程写了自己的module来让node.js多线程,感兴趣的同学可以看看node-threads-a-gogo

由于刚刚接触node.js,文中谬误颇多,希望多家多多批评指教

转载于:https://www.cnblogs.com/dolphinX/p/3475090.html

相关文章:

文本相关CSS

文本相关CSS 属性 word-breakoverflow-wrap(word-wrap)white-spacetext-overflowtext-wrap(目前主流浏览器都不支持)应用 一般断行需求实现文本不换行,以省略号表示超出的部分参考资料属性 word-break 作用:指定非CJK(中日韩)文本的断行规则。&#xff0…

Rocksdb 的优秀代码(三)-- 工业级 线程池实现分享

文章目录前言1. Rocksdb线程池概览2. Rocksdb 线程池实现2.1 基本数据结构2.2 线程池创建2.3 线程池 调度线程执行2.4 线程池销毁线程2.5 线程池优先级调度2.6 动态调整线程池 线程数目上限3. 总结前言 Rocksdb 作为一个第三方库的形态嵌入到各个存储系统之中存储元数据&#…

Java项目:网上电商项目(前后端分离+java+vue+Springboot+ssm+mysql+maven+redis)

源码获取:博客首页 "资源" 里下载! 一、项目简述 本系统功能包括: 一款基于SpringbootVue的电商项目,前后端分离项目,前台后台都有,前台商品展示购买,购物车分类,订 单查…

3月7日 ArrayList集合

ArrayList与数组的区别: 数组是连续的、同一类型数据的一块区域,而集合可以是不连续的、多种数据类型的。 1.ArrayList ArrayList al new ArrayList(); al.Add(3); al.Add(5.09); al.Add("gfdg"); al.Inse…

什么时候出生好?

从年龄来说,女人头一胎的怀孕时间最好在35岁以前,因为过了35岁后不孕和头胎生育缺陷的比例会大幅度升高。那么,从孩子的角度,什么时候出生好?很多人不考虑这个问题,能不能怀上还难说那。迷信的人则追求出生…

数据库搜索与索引

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。 索引的一个主要目的就是加快检索表中数据&#x…

Clion 远程开发 配置

文章目录1. 增加远端服务工具2. 配置远端服务器3. 配置编译选项4. 设置远端开发路径Clion作为C/C语言友好的IDE,除了高效的代码索引 以及 基本的本地开发 能力之外还需要有远程开发能力,即我们工作中的代码处于远端linux服务器之上,通过在本地…

Java项目:朴素风个人博客系统(前后端分离+java+vue+Springboot+ssm+mysql+maven+redis)

源码获取:博客首页 "资源" 里下载! 一、项目简述 本系统功能包括: 基于vue Springboo痼J后端分离项目个人博客系统,注册 登录,首页展示,喜爰图书展示,后台图书维护,个人…

NodeJS+Mongodb+Express做CMS博客系统

楼主正在用业余时间开发中…… ,目前的版本仅支持会员系统,尝鲜一下吧~ hi-blog 一个 nodejsexpressmongodb 的 cms 系统怎么启动 默认你已经安装了 mongodb ;那么你得这样操作:安装项目 -> 初始化管理员 -> 运行项目 1、请…

Piranha实验总结

操作系统:rhel5.8分别在DirectorMaster和DirectorBackup上部署浮动资源(VIP IPVS策略)测试2个Director在DR模式下是否都可以正常工作。测试完成后都撤掉浮动资源。DirectorMaster[rootlocalhost ~]#yum install piranha[rootlocalhost ~]#piranha-passwdNew Passwor…

虚IP切换原理

高可用性HA(High Availability)指的是通过尽量缩短因日常维护操作(计划)和突发的系统崩溃(非计划)所导致的停机时间,以提高系统和应用的可用性。HA系统是目前企业防止核心计算机系统因故障停机的…

vim 键盘宏操作 -- 大道至简

最近利用vim做一些文本处理时 发现vim 支持的键盘宏是一个好东西啊,高效优雅得处理大量需要重复性操作的文本,让人爱不释手!!! 希望接下来对键盘宏的分享能够实际帮助到大家。 后文中描述的一些vim操作会汇集成指令字…

Java项目:家居购物商城系统(java+html+jdbc+mysql)

源码获取:博客首页 "资源" 里下载! 一、项目简述 功能: Java Web精品项目源码,家居商城分类展示,商品展示, 商品下单,购物车,个人中心,后台管理,用…

leetcode:Search in Rotated Sorted Array

题目要求: Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). You are given a target value to search. If found in the array return its index, otherwise return -1. You may a…

解决Debian-7.1下Chrome浏览器字体难看的问题

首先在 Advance Setting 的 font 标签页下做如下配置&#xff1a; 然后在用户目录下创建 .fonts.conf 文件&#xff0c;内容如下&#xff1a; <?xml version1.0?> <!DOCTYPE fontconfig SYSTEM fonts.dtd> <fontconfig><match target"font"&g…

HDU.4903.The only survival(组合 计数)

题目链接 惊了 \(Description\) 给定\(n,k,L\)&#xff0c;表示&#xff0c;有一张\(n\)个点的无向完全图&#xff0c;每条边的边权在\([1,L]\)之间。求有多少张无向完全图满足&#xff0c;\(1\)到\(n\)的最短路为\(k\)。\(n,k\leq 12,\ L\leq10^9\)。 \(Solution\) 考虑暴力&a…

Rocksdb 写入数据后 GetApproximateSizes 获取的大小竟然为0?

项目开发中需要从引擎 获取一定范围的数据大小&#xff0c;用作打点上报&#xff0c;测试过程中竟然发现写入了一部分数据之后通过GetApproximateSizes 获取写入的key的范围时取出来的数据大小竟然为0。。。难道发现了一个bug?&#xff08;欣喜&#xff09; 因为写入的数据是…

Java项目:在线婚纱摄影预定系统(java+javaweb+SSM+springboot+mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a; 前后用户的登录注册&#xff0c;婚纱照片分类&#xff0c;查看&#xff0c;摄影师预 订&#xff0c;后台订单管理&#xff0c;图片管理等等。 二、项目运行 环境配置&am…

Linux Terminal 控制终端的使用

1. Open new Terminal&#xff1a;Ctrl Alt T 或者 Ctrl Shift N 2. Open Tab&#xff1a;Ctrl Shift T 3. Close Tab&#xff1a;Ctrl Shift W 4. Close Window&#xff1a;Ctrl Shift Q 5. Copy : Ctrl Shift C 6. Paste: Ctrl Shift V 7. Full Screen: F11 8.…

如何防止代码腐烂

http://blog.jobbole.com/5643/ 很多团队都有这个问题&#xff0c;一个项目的代码本来开始设计得好好的&#xff0c;一段时间以后&#xff0c;代码就会变得难以理解&#xff0c;难以维护&#xff0c;难以修改。为什么&#xff1f;我一直在思考这个问题。 让我们先看一个人的情况…

CORS在Spring中的实现

CORS: 通常情况下浏览器禁止AJAX从外部获取资源&#xff0c;因此就衍生了CORS这一标准体系&#xff0c;来实现跨域请求。 CORS是一个W3C标准&#xff0c;全称是"跨域资源共享"&#xff08;Cross-origin resource sharing&#xff09;。它允许浏览器向跨源(协议 域名…

从BloomFilter到Counter BloomFilter

文章目录前言1. Traditional BloomFilter2. Counter BloomFilter本文traditional bloomfilter 和 counter bloomfilter的C实现 均已上传至&#xff1a; https://github.com/BaronStack/BloomFilter 前言 Bloomfilter 是一个老生常谈的数据结构&#xff0c;应用在存储领域的各…

进程、线程、多线程相关总结

进程、线程、多线程相关总结 一、说说概念 1、进程&#xff08;process&#xff09; 狭义定义&#xff1a;进程就是一段程序的执行过程。 广义定义&#xff1a;进程是一个程序关于某个数据集合的一次运行。它是操作系统动态执行的基本单元&#xff0c;在传统的操作系统中&#…

Java项目:在线蛋糕商城系统(java+jsp+jdbc+mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a; 主页显示热销商品&#xff1b;所有蛋糕商品展示&#xff0c;可进行商品搜 索&#xff1b;点击商品进入商品详情页&#xff0c;具有立即购买和加入购物 车功能&#xff0c;可…

业界对生成图片缩略图的做法归纳

网站如果有很多用户上传图片(相册&#xff0c;商品图片)&#xff0c;一般的做法是将用户图片保存在磁盘上面(数据库中记录图片的地址)。用户上传的时候按照原图、中图、小图等各个尺寸都生成一份保存在磁盘上。比如php的网店系统echsop就是这么做的&#xff0c;而shopex之类也大…

thinkPHP5.0 URL路由优化

在tp中访问页面的时候URL地址是 域名/模块/控制器/方法&#xff0c;在点击首页的时候URL是 域名/index/index/index 而不是只显示域名&#xff0c;这样不利于SEO&#xff0c;而且强迫症的我看着很不爽&#xff0c;这个时候我们需要优化路由 Route::rule(路由表达式,路由地址,请…

Rocksdb 获取当前db内部的有效key个数 (估值)

文章目录1. 基本接口2. Memtable key个数统计3. Immutable Memtable key个数统计4. Sstables key个数统计5. 疑问Rocksdb因为是AppendOnly 方式写入&#xff0c;所以没有办法提供db内部唯一key个数的接口&#xff08;可能存在多版本的key&#xff0c;对用户来说只有一个userkey…

Java项目:网上花店商城系统(java+jsp+servlert+mysql+ajax)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a; 一套完整的网上花店商场系统&#xff0c;系统支持前台会员的注册 登陆系统留言&#xff0c;花朵的品种选择&#xff0c;详情浏览&#xff0c;加入购物 车&#xff0c;购买花…

使用Uboot启动内核并挂载NFS根文件系统

配置编译好内核之后&#xff0c;将生成的内核文件uImage拷贝到/tftpboot/下&#xff0c;通过tftp服务器将内核下载到开发板&#xff0c;使用命令&#xff1a;tftp 31000000 uImage.下载完成之后配置bootargs环境变量&#xff1a;setenv bootargs noinitrd consolettySAC0,11520…

Centos系统上安装php遇到的错误解决方法集锦

Centos系统上安装php遇到的错误解决方法集锦1.configure: error: xml2-config not found. Please check your libxml2 installationyum install libxml2 libxml2-devel2.configure: error: Cannot find OpenSSL’s yum install openssl openssl-devel3.configure: error: Pleas…