网站首页 > 技术文章 正文
本概述介绍了Node.js中阻塞和非阻塞调用之间的区别。本概述将参考事件循环和libuv,但不需要事先了解这些主题。假设读者对JavaScript语言和Node.js回调模式有基本的理解。
“I/O”主要指与libuv支持的系统磁盘和网络的交互。
阻塞
阻塞是指Node.js进程中额外JavaScript的执行必须等待非JavaScript操作完成。发生这种情况是因为在发生阻塞操作时,事件循环无法继续运行JavaScript。
在Node.js中,由于CPU密集型,而不是等待非JavaScript操作(如I/O),而表现出较差性能的JavaScript通常不被称为阻塞。Node.js标准库中使用libuv的同步方法是最常用的阻塞操作。原生模块也可能具有阻塞方法。
Node.js标准库中的所有I/O方法都提供非阻塞的异步版本,并接受回调函数。有些方法也有阻塞的对应方法,它们的名称以Sync结尾。
对比代码
阻塞方法同步执行,非阻塞方法异步执行。
以文件系统模块为例,这是一个同步文件读取:
const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read
一个异步示例:
const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
if (err) throw err;
});
第一个例子看起来比第二个简单,但缺点是第二行会阻止任何附加JavaScript的执行,直到整个文件被读取。请注意,在同步版本中,如果抛出错误,则需要捕获错误,否则进程将崩溃。在异步版本中,由作者决定是否应该抛出错误。
我们稍微扩展一下我们的示例:
const fs = require('fs');
const data = fs.readFileSync('/file.md'); // blocks here until file is read
console.log(data);
moreWork(); // will run after console.log
一个类似但不等价的异步示例:
const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
if (err) throw err;
console.log(data);
});
moreWork(); // will run before console.log
在上面的第一个例子中,console.log将在moreWork()之前调用。在第二个例子中,fs.readFile()是非阻塞的,因此JavaScript可以继续执行,并将首先调用moreWork()。在不等待文件读取完成的情况下运行moreWork()的能力是实现更高吞吐量的关键设计选择。
并发性和吞吐量
Node.js中的JavaScript执行是单线程的,因此并发是指事件循环在完成其他工作后执行JavaScript回调函数的能力。任何期望以并发方式运行的代码都必须允许事件循环在非JavaScript操作(如I/O)发生时继续运行。
作为一个例子,让我们考虑这样一种情况,即对web服务器的每个请求需要50毫秒才能完成,其中45毫秒是可以异步完成的数据库I/O。选择非阻塞异步操作可以为每个请求释放45ms的时间来处理其他请求。仅仅通过选择使用非阻塞方法而不是阻塞方法,这在容量上是一个显著的差异。
事件循环不同于许多其他语言中的模型,在这些语言中可以创建额外的线程来处理并发工作。
混合阻塞和非阻塞代码
在处理I/O时,应该避免一些方式。让我们看一个例子:
const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
if (err) throw err;
console.log(data);
});
fs.unlinkSync('/file.md');
在上面的例子中,fs.unlinkSync()可能在fs.readFile()之前运行,这将在实际读取file.md之前删除它。
更好的方法是,它完全不阻塞,并保证以正确的顺序执行:
const fs = require('fs');
fs.readFile('/file.md', (readFileErr, data) => {
if (readFileErr) throw readFileErr;
console.log(data);
fs.unlink('/file.md', unlinkErr => {
if (unlinkErr) throw unlinkErr;
});
});
上面在fs.readFile()的回调中放置了对fs.unlink()的非阻塞调用,这保证了操作的正确顺序。
猜你喜欢
- 2024-10-25 什么是喉梗阻 反流性食管炎嗓子疼怎么办
- 2024-10-25 阻塞列队详解!让你轻松理解阻塞列队
- 2024-10-25 【健康科普】认识阻塞性睡眠呼吸暂停低通气综合征
- 2024-10-25 气象科普|阻塞高压为何方神圣?后期它将给我国制造多轮冷空气
- 2024-10-25 非阻塞算法CAS 非阻塞函数
- 2024-10-25 为什么网络 I/O 会被阻塞?I/O 到底是什么?
- 2024-10-25 如何用Java设计阻塞队列,再说说ArrayBlocking和LinkedBlocking
- 2024-10-25 使用 Python Socket 实现非阻塞 I/O入门讲解
- 2024-10-25 梗阻性无精子症:多种选择,何为最佳?
- 2024-10-25 焦耳小偷 一个神奇的电路 焦耳小偷电路需要注意的地方
你 发表评论:
欢迎- 02-26Docker目录说明之 /var/lib/docker
- 02-26家用nas最常用的docker容器及部署方法
- 02-26Docker快速上手笔记
- 02-26怎样在Python中操作Docker容器?
- 02-26手把手教你搭建LLM模型知识库,开启AI智慧大门
- 02-26Docker容器是个啥?和VM有什么区别?
- 02-26Docker入门指南:从新手到容器大师
- 02-26带你一文搞懂 Docker
- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)