nodejs中的阻塞和非阻塞(https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/)

一、简述

这片文章主要讲述Nodejs中的阻塞和非阻塞回调,涉及到事件循环和libuv。但是你并不需要提前了解这些知识,你只需要具备js和Nodejs回调模式的基础。

"I/O"指的是与系统硬盘的交互以及libuv所支持的网络交互。

1.Blocking阻塞

1.1代码对比

阻塞指的是Nodejs中的js进程必须等待非js操作完成之后才能执行,原因是当阻塞操作发生时,事件循环无法持续运行。

在nodejs中,由于cpu内存不够而造成js运行性能差的情况不叫阻塞,只有js在等待非js操作(例如:I/O)完成时才运行的情况叫做阻塞。Nodejs标准库中的同步方法是常用的阻塞操作。原生模块中也有阻塞方法。

Nodejs标准库中的所有IO方法都提供了异步非阻塞的版本,这些方法接收回调函数。一些方法有其对应的阻塞版本,以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;
});

阻塞方法相对非阻塞方法来说比较简单,但是,有其缺点:它会等到文件读取完成后才执行后续操作。需要注意的是,在阻塞方法中,错误必须被捕获,否则程序就会崩溃。但是在非阻塞版本中,可以不进行错误的捕获。

2.并发性和吞吐量(Concurrency and Throughput)

Nodejs中执行js是单线程的,所以,并发性指的是执行事件回调函数的能力。并发性强的代码即使在非js操作发生的时候,也能继续执行事件回调。
举例:每一个到达服务器的请求会花费50ms完成,其中的45ms用来对数据库的异步读取。选择非阻塞的异步方法可以释放服务器45ms的时间去处理其他请求。这是选择非阻塞方法的最明显的优势。
js中的事件循环模型与其他语言不同的地方在于:其他语言可以使用多线程来处理并发性工作。


3.混合阻塞方法和非阻塞方法的危险之处

当处理IO时有一些需要避免的模式:

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方法之前运行,这样就会导致,文件在没有读取完成前被删除。最好的方法如下:

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;
  });
});





你可能感兴趣的:(node)