Nodejs非阻塞原理请教

Nodejs非阻塞原理请教

各位 我发现,因为node是单线程,所以当多个人同时访问同一个页面的时候,对应的requestHander是顺序执行的,也就是说如果a的页面没有加载完,那么b的页面就不能开始加载。请教各位这个问题怎么解决。 另外,有没有关于node事件机制的文章,想了解一下node是怎样支持高并发的。

多谢

10 回复

当然可以。根据你的问题,我可以帮你理解Node.js的非阻塞I/O模型以及它如何处理高并发的情况。

Node.js 非阻塞 I/O 原理

Node.js 是基于事件驱动的单线程架构,这意味着它能够高效地处理大量并发请求而不必为每个请求创建一个新的线程。相反,Node.js 使用事件循环(Event Loop)来管理异步操作,并且通过回调函数、Promises 或者 async/await 来处理这些异步操作的结果。

示例代码

假设我们有一个简单的HTTP服务器,它需要读取文件并返回其内容:

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

const server = http.createServer((req, res) => {
    // 读取文件,使用非阻塞方式
    fs.readFile('./data.txt', (err, data) => {
        if (err) {
            console.error(err);
            res.writeHead(500);
            res.end('Internal Server Error');
            return;
        }
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end(data);
    });
});

server.listen(3000, () => {
    console.log('Server running at http://localhost:3000/');
});

在这个例子中,fs.readFile 方法是非阻塞的。这意味着即使读取文件的过程需要一些时间,Node.js 不会在此过程中挂起,而是继续处理其他请求。一旦文件读取完成,就会调用传入的回调函数。

解决方案

你提到的 ab 页面不能同时加载的问题,实际上是因为 fs.readFile 这种非阻塞操作导致的。尽管Node.js是单线程的,但它的非阻塞特性允许它在等待一个耗时的操作(如文件读取或数据库查询)时,去处理其他请求。

如果你发现某些操作仍然导致了阻塞,可能是因为这些操作本身是阻塞的,或者你正在使用同步方法(例如 fs.readFileSync)。避免这种情况的方法就是始终使用非阻塞API,并且正确地处理回调。

关于Node.js的事件机制

Node.js的核心是事件驱动的,所有的网络操作和文件系统调用都是非阻塞的。这使得Node.js非常适合处理高并发场景。你可以阅读以下资源来深入了解:

  1. 官方文档 - Node.js 文档
  2. 深入浅出Node.js - 书籍,详细介绍了Node.js的内部机制。
  3. Node.js 官方博客 - 提供了许多关于性能优化和最佳实践的文章。

希望这些信息对你有所帮助!如果你有任何进一步的问题,请随时提问。


如果a页面没有加载完成,那么此时如果CPU处于空闲状态,则b页面可以同时开始加载 这就是异步,硬盘跟CPU可以并行运行

你的意思是说,要使用那个cluster这类的module,发挥多核的优势? 如果cpu有4个,那么第5个人来了,是不是会阻塞等待第一个人加载完成呢?

多谢你的回复

因为我试验之后发现,如果page 1 的handler需要大量运算,也就是阻塞了,这时a访问page 1 ,处于等待状态,如果这时候b访问任何page,都是需要等待a完成的。

将page 1的handler单独拿到一个child process, 如果ab同时访问page 1,那么还是阻塞等,如果a访问page 1,b访问page 2,那么才能并行。

不知道各位怎么看这种情况?

这是不是说,一旦某个page有大量高清pic要load,那么后面的人都要等待?

这个太可怕了

应该是我技术的问题吧,请各位多多指正

处理时间和加载时间是不一样的,一个是同步一个是异步

你说的是下载大图片吗,node只需要把数据流一点点扔给操作系统就算完事,不需要同步处理 所以可以同时下载多张图片

但是请求的处理时间是同步的,如果页面处理的计算时间需要2毫秒,那么并发能力就是每秒500左右

嗯,因為我使用while( new Date(),getTime() < currentTime + milliSecends);的方式阻塞了requestHandler,所以下一個請求只能串行執行了。

多謝你的回覆

祝好

任务队列+事件循环

够简洁,够准确:)

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它使用了事件驱动、非阻塞 I/O 模型,使其轻量又高效。Node.js 的核心原理在于它的事件循环(Event Loop)机制,通过这种机制,Node.js 可以处理大量并发请求而不需要为每一个连接创建一个单独的线程。

对于你的问题,Node.js 的单线程模型并不会导致请求排队等待。实际上,Node.js 在处理 I/O 操作时是非阻塞的。例如,当你处理 HTTP 请求时,Node.js 不会因为一个请求未完成而阻止其他请求的处理。相反,当 Node.js 处理一个 I/O 操作(如读取文件或网络请求)时,它会将该操作委托给底层的 C++ 代码来异步执行,并立即返回来处理其他请求。

这里有一个简单的 Node.js 示例,展示了如何处理多个并发请求:

const http = require('http');

const server = http.createServer((req, res) => {
    // 假设这是一个耗时的操作
    setTimeout(() => {
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end('Hello World');
    }, 3000);  // 模拟耗时3秒的I/O操作
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

在这个例子中,即使每个请求需要处理3秒钟的时间,服务器也可以并行地处理多个请求。例如,如果两个用户几乎同时访问该服务器,Node.js 将同时启动两个 setTimeout 函数,然后返回来处理其他请求。这两个 setTimeout 函数将在后台异步运行,不会阻塞其他请求的处理。

关于 Node.js 的事件机制,可以阅读官方文档中的这一部分,以及深入了解Event Loop的工作方式。这些资源能够帮助你理解 Node.js 如何高效地处理高并发场景。

回到顶部