Nodejs 《nodejs入门》中提到的非阻塞,有一句代码不明白

Nodejs 《nodejs入门》中提到的非阻塞,有一句代码不明白

exec(“find /”, { timeout: 10000, maxBuffer: 20000*1024 }, function (error, stdout, stderr) { response.writeHead(200, {“Content-Type”: “text/plain”}); response.write(stdout); response.end(); });

书上介绍"find /"将花费10s,但是我试验时运行很快,几乎试验不出“非阻塞”这个概念。我在想,是否“find /”的问题,根目录只有4个文件而已。难道仅是文件不够多,使得“find /”无需超时10s吗,只是几毫秒就完成了。如果真的是这种,这本书太不照顾新手了,用别的例子试验非阻塞岂非更好!


7 回复

Node.js 《Node.js入门》中提到的非阻塞,有一句代码不明白

问题描述

在阅读《Node.js入门》时,遇到了以下代码示例:

exec("find /", 
    { timeout: 10000, maxBuffer: 20000 * 1024 }, 
    function (error, stdout, stderr) {
        response.writeHead(200, {"Content-Type": "text/plain"});
        response.write(stdout);
        response.end();
    }
);

书中提到"find /"命令需要花费大约10秒时间执行,但我实际运行时发现它几乎是瞬间完成的,这让我对“非阻塞”的理解产生困惑。我怀疑可能是由于根目录(/)下的文件数量较少,导致find /命令几乎立刻完成。这让我觉得书中举的例子可能不太适合用来说明“非阻塞”的概念。

解释

首先,让我们明确一下什么是“非阻塞”。在Node.js中,“非阻塞”意味着某些操作不会阻塞程序的执行,而是异步地执行,并且可以继续处理其他任务。例如,在上面的代码中,exec函数用于执行一个系统命令(在这里是find /),但它不会阻塞Node.js事件循环,允许程序继续执行其他任务。

示例代码

为了更好地理解“非阻塞”,我们可以使用一个更合适的例子,比如读取一个大文件。假设我们有一个名为large-file.txt的大文件,我们希望读取它的内容而不阻塞程序的执行。

const fs = require('fs');
const http = require('http');

http.createServer((req, res) => {
    fs.readFile('large-file.txt', 'utf8', (err, data) => {
        if (err) throw err;
        
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.write(data);
        res.end();
    });
}).listen(3000, () => console.log('Server running on port 3000'));

在这个例子中,fs.readFile是一个异步方法,它读取文件的内容而不会阻塞服务器的响应能力。即使文件非常大,服务器仍然可以继续处理其他请求。

结论

通过上述例子,我们可以看到Node.js的“非阻塞”特性是如何工作的。虽然find /命令在你的环境中可能很快完成,但通过使用fs.readFile读取大文件,可以更清楚地看到Node.js如何异步处理任务,从而提高应用程序的整体性能和响应性。


你没仔细看书啊, 我记得那上面说, 根目录有海量文件!!

我觉得看书不够仔细,虽然node入门我看过之后都过了很久,但是很启蒙的一本书,其中的原话是这样的: 我们这里“ls -lah”的操作其实是非常快的(除非当前目录下有上百万个文件) ... 为了让效果更加明显,我们想象一个更耗时的命令: “find /”,它在我机器上需要执行1分钟左右的时间,然而,尽管在请求处理程序中,我把“ls -lah”换成“find /”,当打开/start URL的时候,依然能够立即获得HTTP响应 —— 很明显,当exec()在后台执行的时候,Node.js自身会继续执行后面的代码。并且我们这里假设传递给exec()的回调函数,只会在“find /”命令执行完成之后才会被调用。

我也在这个地方遇到问题了,他说“会花 10 秒钟的时间才载入”,感觉这个十秒钟是按照:timeout: 10000,来的,所以个人认为是这个timeout没起作用,不知道同学这一个半月之后有没有更好的认识~嘿嘿~感谢赐教~

你用 exec(‘ping 0.0.0.0 -n 10’) 来测试

sleep(10000)

在Node.js中,“非阻塞”指的是在执行I/O操作(如文件读取、网络请求等)时,程序不会等待这些操作完成才继续往下执行。相反,程序会继续处理其他任务,直到I/O操作完成,然后通过回调函数来处理结果。

在你提供的代码中,exec 方法用于执行一个系统命令(在这个例子中是 find /),并提供了三个参数:

  • 第一个参数是要执行的命令。
  • 第二个参数是一个选项对象,可以设置一些执行参数,比如 timeoutmaxBuffer
  • 第三个参数是一个回调函数,当命令执行完成后会被调用。这个回调函数接收三个参数:error(如果有错误发生)、stdout(标准输出)和 stderr(标准错误)。

这段代码的作用是执行 find / 命令来查找根目录下的所有文件,并将结果返回给客户端。这里的关键点在于 exec 方法是非阻塞的。即使 find / 命令需要较长时间才能完成,Node.js 也不会等待它的结果而停止执行其他任务。因此,这展示了 Node.js 的非阻塞特性。

你提到的 find / 命令可能由于你的测试环境文件数量较少,导致命令执行非常快。但这不影响对非阻塞特性的理解。你可以尝试在更大的文件系统或不同的操作系统环境中测试 find 命令,以便更好地体验非阻塞的效果。此外,你可以考虑使用一些其他命令,例如 sleep 来模拟更长时间的 I/O 操作,以便更清楚地看到非阻塞的效果。

const util = require('util');
const exec = util.promisify(require('child_process').exec);

async function runCommand() {
    try {
        const { stdout, stderr } = await exec("sleep 10"); // 模拟长时间操作
        console.log('stdout:', stdout);
        console.log('stderr:', stderr);
    } catch (error) {
        console.error(`Error executing command: ${error}`);
    }
}

runCommand(); // 调用该异步函数

上面的代码使用了 util.promisifyexec 函数转换为返回 Promise 的形式,从而可以使用 async/await 语法简化代码。这样你可以更容易地观察到非阻塞的效果。

回到顶部