我一直在阅读尽可能多的NodeJs代码,但是我对以下内容有些困惑:
Node单线程究竟意味着什么?非阻塞I/O又是什么意思?我可以通过生成子进程来实现第一个,通过使用async库来实现第二个。但我希望清楚地了解它的含义以及非阻塞I/O如何仍然会使你的应用程序变慢。
我一直在阅读尽可能多的NodeJs代码,但是我对以下内容有些困惑:
Node单线程究竟意味着什么?非阻塞I/O又是什么意思?我可以通过生成子进程来实现第一个,通过使用async库来实现第二个。但我希望清楚地了解它的含义以及非阻塞I/O如何仍然会使你的应用程序变慢。
我会尽力解释。
单线程意味着Node.js Javascript运行时在特定时间点仅执行从所有已加载的代码中选择的一段代码。实际上,它从某个地方开始,并通过所有指令(调用堆栈)向下工作,直到完成。当它执行代码时,没有任何东西可以打断这个过程,所有的I/O都必须等待。谢天谢地,大多数调用堆栈相对较短,我们在Node.js中做的很多事情更多是“簿记”类型而不是CPU密集型。
然而,由于单线程性质,任何需要花费很长时间的指令都会成为系统响应能力的巨大问题。运行时每次只能执行一件事情,因此必须等待所有内容,直到该指令完成。如果任何“I/O”指令(比如从磁盘读取)会阻塞执行,则系统将在那个时间不必要地不可用。
但值得庆幸的是,我们有非阻塞式I/O。
与其等待文件被读取:
console.log(readFileSync(filePath))
你可以编写你的代码,使其不等待文件被读取:
readFile(filePath)
调用readFile
几乎立即返回(可能在几纳秒内),因此运行时可以继续执行接下来的指令。但是,如果readFile
调用在数据被读取之前返回,那么readFile
调用就无法返回文件内容。这就是回调函数的作用:
readFile(filePath, function(err, contents) { console.log(contents))
仍然,readFile
调用几乎立即返回。运行时可以继续执行。它将完成当前工作和所有其后的指令。传递的函数除了存储对它的引用外,没有什么其他用处。
稍后(可能是10ms、100ms或者1000ms)读取文件完成时,回调函数会被调用,并将文件完整内容作为第二个参数传递。在此之前,运行时可以完成任意数量的其他工作批次。
现在,我来回应一下关于生成子进程和Async库方面的评论。您两点都是错误的:
生成子进程是让Node.js使用多个CPU内核的一种方法。单线程的Node.js没有使用多个内核的目的。但是,如果您使用的是多核计算机,则可以启动多个Node.js进程以利用所有这些内核。
Async库不会为您提供非阻塞I/O,Node.js已经为您提供了该功能。Node.js自己没有解决的是如何轻松处理来自多个回调的数据。Async库可以在这方面提供很大帮助。
由于我不是Node.js内部专家,欢迎指正!
相关问题: