谈谈NodeJS异步

本文探讨了NodeJS中的异步I/O,解释了同步与异步的区别,并通过实例介绍了函数回调、事件监听、订阅/发布模式和Promise,以及最新的async/await。NodeJS的异步特性使其在处理I/O密集型任务时表现出色,但面对CPU密集型任务时,可通过C/C++扩展或子进程充分利用CPU。
摘要由CSDN通过智能技术生成

同步与异步

一谈起Node,了解过的人会想起是利用异步IO实现高性能后台,那么什么是异步IO呢?
异步IO与同步IO的区别是什么呢?举个例子:在生活中,大家每天都会用到微信来进行聊天。那么某个时间有两个人来跟你聊天,同步与异步会有不同的表现(单线程的情况下)。

  • 同步:同步的做法是先选择一个比较先与你聊天的,把整个天都给聊完了,最后确定对方与你没有什么好聊的。ok接下去跟另外一个人进行聊天。
  • 异步:异步的做法是选择同时和这两个人进行聊天,每一次把信息发出去,等待对方回信息的时间内你都可以做其他事情,比如与编辑回复另外人信息。

这两个就是同步与异步的区别。只要不傻,肯定都是以第二种方式进行聊天。很多人会想,我为什么要在这里讲同步于异步的区别,既然异步这么好,开发的语言应该用到的是异步吧?
其实不然,很多开发的语言用到是同步。java处理并发是用到多线程(虽然java有一个nio处理异步,但是之前是很少人用到的,现在应该逐渐有人去重视这个),每个线程的执行是同步的。如果在这个线程中进行读取磁盘文件,在读取的过程中这个线程的资源是没有利用的。这个是同步的缺点。那为什么不使用异步呢?!异步的开发成本要高于同步,一般执行顺序不符合正常的逻辑思维(一般不是从上到下)。先说这么多,后面再讲明原因。

异步I/O

关于异步I/O,向前端开发工程师讲起来会比较简单一点,因为前端页面可以理解为是基于事件驱动的。用ajax发起请求对于前端工程师来说是更熟悉不过的

$.post('/url', {
   title: '深入浅出Node.js'}, function (data) {
   
  console.log('收到响应');
});
console.log('发送Ajax结束'); 

执行这一段代码的时候,假设后台是响应成功的,执行顺序是先打印“发起Ajax结束”然后再“收到响应”。这个很好理解,执行第二次打印的时候是当后台返回数据说响应成功后执行的。
我们只知道它将在这个异步请求结束后执行,但并不知道具体的时间点。异步调用中对于结果值的捕获是符合“Don’t call me, I will call you”的原则的,这也是注重结果,不关心过程的一种表现。
下面是ajax请求时候的图解。
Ajax
那么异步IO处理文件读取是怎么一回事呢?
Node调用文件读取需要导入fs模块,在浏览器中,js是无法直接访问主机上的文件的,是由于安全方面的考虑。但是node上是可以的。其代码如下:

const fs = require('fs');
fs.readFile('文件路径', (err, file) => {
   
	console.log('文件读取完毕');
});
console.log('发起文件读取');

同样,这里发起文件读取是执行在文件读取完毕之前的。跟ajax类似,其图解也是类似的。
在这里插入图片描述
以上代码如果同时读取文件A和文件B,会几乎同时对A和B发起读取,然后线程可以执行其他代码,待到AB读取回调的时候,在执行相应的回调。这样就是异步IO的好处,可以原本读取一个文件的时间内读取更多的文件(假设文件同样大小)。
Node在这方面做得不错决定了Node比其他大多数后端语言的优势在于对IO密集型业务会有更好的表现。通常,说Node擅长I/O密集型的应用场景基本上是没人反对的。Node面向网络且擅长并行I/O,能够有效地组织起更多的硬件资源,从而提供更多好的服务。
I/O密集的优势主要在于Node利用事件循环的处理能力,而不是启动每一个线程为每一个请求服务,资源占用极少。
由于JavaScript是单线程语言,有人会问Node在cpu密集型业务逻辑中是不是表现不是很好。在JavaScript层面上讲,是对的。
换一个角度,在CPU密集的应用场景中,Node是否能胜任呢?实际上,V8的执行效率是十分高的。单以执行效率来做评判,V8的执行效率是毋庸置疑的。
这里引用《深入浅出nodejs》的一个小实验来进行。
那里用斐波那契数列用各种脚本语言进行试验,其中用java和go语言作为参考,得出结果如下图:

在这里插入图片描述
可以看出Node中的C++模块表现还是挺不错的。
分析如下:
这样的测试结果尽管不能完全反映出各个语言的性能优劣,但已经可以表明Node在性能上不俗的表现。从另一个角度来说,这可以表明CPU密集型应用其实并不可怕。CPU密集型应用给Node带来的挑战主要是:由于JavaScript单线程的原因,如果有长时间运行的计算(比如大循环),将会导致CPU时间片不能释放,使得后续I/O无法发起。但是适当调整和分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起,这样既可同时享受到并行异步I/O的好处,又能充分利用CPU。
关于CPU密集型应用,Node的异步I/O已经解决了在单线程上CP

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值