当我们知道 I/O 操作和创建新线程的开销是巨大的!
对于一个网站,后台大多不需要进行复杂的计算,我们的程序大多时间花费在 I/O 读取上。
看到一个数据:IO 操作可以比数据处理慢几个数量级。高端 SSD 固态硬盘的读取速度可以达到 200mb-700mb/s; 读取 1000 字节需要 1.4 微秒。而在此期间,2GHZ 频率的 CPU 可以执行 28000 个指令处理周期。而网络数据的 IO 甚至更慢!
当采用多线程时,为每一个请求开启一个新的线程(Apache 就是这样做的)。当并发增多,线程的消耗会十分严重。
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
- var fs = require("fs");
- fs.readFile("./testfile", "utf8",
- function(error, file) {
- if (error) throw error;
- console.log("我读完文件了!");
- });
- console.log("我不会被阻塞!");
用 node 执行以下代码,会先输出我不会被阻塞,再输出我读完文件了
一个知乎的回答:
这是 node 虽然为单线程,但是可以处理大并发,高吞吐量的核心。一个事件轮询拥有下面三个组件
在 nodejs 中,只有一个主线程(也就是前面说的单线程)来不断读取轮询(书中称为调用 I/O 观察者)队列中是否有事件。
而对于读取文件,HTTP
请求等(现代 cpu 处理能力很强,事件处理相当快,导致运行速度下降的瓶颈在 I/O)比较容易堵塞的事件,就在这个单线程中执行肯定会造成堵塞,所以 Event Loop
会把这类型的事件交给底层的线程池执行,并给予线程池一个回调函数,当线程池操作
完成这堵塞任务后,便把结果和回调函数一起再放入轮询队列中。
来源: