2016-01-23 253 views
1

在过去的日子里,我一直在研究如何理解Node.js基于事件的风格如何处理比传统的多线程方法更多的并发请求。最后,所有关于内存占用和内存切换的内容都减少了,因为Node.js只使用了几个线程(V8单线程和一堆C++工作线程以及libuv的主线程)。在Node.js中扮演V8引擎的角色是什么?

但是如何处理大量带有几个线程的请求,因为最后一些线程必须被阻塞等待,例如数据库读取操作。 我认为这个想法是:而不是同时阻塞客户端线程和数据库线程,只有数据库线程被阻塞,并在客户端线程结束时提醒客户端线程。

这就是我理解Node.js的工作原理。

我一直在想,是什么赋予Node.js处理HTTP请求的能力。 根据我阅读到现在为止,我的理解是libuv是谁做的工作:

把手代表能够积极而执行某些操作 长寿命的对象。一些示例:当处于活动状态时,准备句柄的每个循环迭代都会调用一次 回调,并且a TCP 服务器句柄在每次有新连接时都会调用它的连接回调。

enter image description here

所以,这是等待进入的HTTP请求的线程是libuv的主线程执行所述libuv事件循环。

所以,当我们在写

const http = require('http'); 

const hostname = '127.0.0.1'; 
const port = 1337; 

http.createServer((req, res) => { 
    res.writeHead(200, { 'Content-Type': 'text/plain' }); 
    res.end('Hello World\n'); 
}).listen(port, hostname,() => { 
    console.log(`Server running at http://${hostname}:${port}/`); 
}); 

...我在libuv投入,将在V8引擎,当请求中执行的回调?

的事件的顺序将然后是

  1. 一个TCP数据包到达
  2. 操作系统创建一个事件,并发送至事件循环
  3. 事件循环处理该事件并创建一个V8事件

如果我在处理请求的匿名函数中执行阻塞代码,我将阻塞V8线程。

为了避免这种情况,我需要执行将在另一个线程中执行的非阻塞代码。我想这“另一个线程”是libuv的主线程,其中

网络I/O始终是在单个线程执行,每次循环的线程

这个线程不会阻止,因为使用OS系统调用是异步的。

的epoll在Linux上,在OSX和其他BSD系统的kqueue,事件端口在SunOS 和IOCP在Windows

我也假设http.request是使用libuv这个achive。

相似,如果我需要做一些文件I/O而不阻塞V8线程
我将使用Node的FileSystem模块。这次libuv主线程不能以非阻塞的方式处理这个问题,因为操作系统不提供这个功能。

与网络I/O,没有特定于平台的文件I/O原语 libuv可以依靠,所以目前的办法是运行阻止文件 I/O操作的线程池。

在这种情况下,为了不阻止libuv事件循环,需要经典的线程池。

现在,如果我需要查询数据库,所有不阻止V8线程和libuv线程的责任都在驱动程序开发人员的手中。 如果驱动程序不使用libuv,它将阻止V8引擎。

相反,如果它使用libuv但基础数据库不具有异步功能,那么它将block a worker thread

最后,如果数据库提供异步功能,它只会阻塞数据库线程。 (在这种情况下,我可以根本避免libuv并直接从V8线程调用驱动程序)

如果这个结论正确描述,尽管以简单的方式说明了libuv和V8在Node.js中一起工作的方式,我无法看到使用V8的好处,因为我们可以直接在libuv中完成所有工作(除非目标是为开发人员提供一种允许以更简单的方式编写基于事件的代码的语言)。

回答

0

从我所知道的差异主要是异步I/O。在传统的每请求处理或每请求线程服务器中,I/O(最显着的是网络I/O)传统上是同步I/O。 Node.js使用的线程少于Apache或其他,并且它可以处理流量,主要是因为它使用异步网络I/O。

Node.js需要V8来实际解释JS代码并将其转换为机器代码。 Libuv需要做真正的I/O。我不知道更多:)

0

有一个很好的帖子关于node.js V8引擎:How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code。它解释了引擎的许多深入细节和使用它的一些重要建议。

简而言之,V8 engine(和其他javascript engines)所做的就是执行javascript代码。然而,与其他人相比,V8 engine获得了高性能执行。

V8将JavaScript代码翻译成更高效的机器代码,而不是使用解释器的 。它通过实现JIT(Just-In-Time)编译器将JavaScript代码编译成机器代码 ......

0

I/O通过libuv进行非阻塞和异步操作,其中底层使用像epoll或类似的OS原语,具体取决于平台,以使I/O无阻塞。当fd上的事件(例如tcp套接字)发生时,Nodejs事件循环获得排队的事件

相关问题