不是说node不能利用多核心CPU吗?
发布于 5 年前 作者 jyk0011 7179 次浏览 来自 问答

初学node,听说他是单线程的,只能使用一个核心,如果CPU是多核心的,那么只能用一个核心,其他核心无法使用。对吧?

发现了一个问题。本来是想看看精确计时的问题,但是在死循环的时候,看了一下CPU的使用情况,发现四个核心都利用起来了。 反复试验了几次都是这样,没有其他软件运行。不知道是怎么回事。

var i=0; var j=0;

var star = (new Date()).getTime(); //普通计时 var star2 = time(); //精确计时 var star3 = time(); //精确计时

while (true){ i++;j++;

var t = time() - star2;
var msg = i + '_' + (new Date()).getTime() + '_' + time() + '_' +t;
//计算每循环100次需要的时间,运行结果可得,时间并不一致
if (j==100){
    var t2 = (new Date()).getTime() - star;
    var t3 = time() - star3;
    console.log(msg + '_' + t2+ '_' + t3); //每百次用时
    star = (new Date()).getTime();
    star3 = time();
    j=0;
}
else {
    console.log(msg);
}

star2 = time();

} function time(){ var diff = process.hrtime(); return diff[0] * 1000 + diff[1] / 1e6; // nano second -> ms

}

time10.png

开始运行,四个核的使用率都上来了,关闭运行,四个核的使用率都下来了。

是不是我理解错了?

27 回复

非官方回答,我的猜测是:nodejs是单进程,不是单核心。系统会根据你的需求来动态分配你的进程运行核心的

注意,这个只是我的猜测。

  1. 单进程,主线程只有一个,但是辅助线程(IO游击队) 有很多。
  2. 可以通过 pm2 或者 docker 启动多个实例,榨干 CPU 性能。
  3. 当然,也可以开启多多线程模式,或者 使用 工作线程。

事实上,node 减少了 线程通信的损耗,反而在很多场景上提升了性能。

@zuohuadong 代码很简单,没有IO操作,没有数据库访问,只有两个获取时间的函数。这个开启辅助线程了吗? 我也觉得node减少多线程的通讯是好事。

@pzzcn 这个,单进程是如何利用多核心的呢?是node自己实现的,还是操作系统实现的呢?

V8是多线程,不过楼主的代码会在 V8 里面执行么?

@jyk0011 那可以考虑工作线程 (node10 加入的) 或者多启动几个实例

我猜测是CPU的问题,跟单线程没有关系。 之前看过现代CPU设计的一个章节,就是讲CPU的自动负载设计,大概的意思我看了一下其实和node的cluster很类似,由一个Master来分配到多个核心中,不过要高级点实现自动时间分片和自动线程调度。这应该是CPU自己调度,进行负载均衡了。 你可以换其他语言试试看看,不开线程是不是也能均衡负载,如果真开满线程照道理应该拉满,而不是还有空档。

@waitingsong nodejs不都是由v8解析的吗?还可以用其他的执行吗?看来要看看《深入浅出》里面对v8的介绍了。话说这本书挺难肯的。

@zuohuadong 前几天在官网下载的安装程序,是v8.7.0 的。工作线程不是只有一个吗?启动一个实例都没有弄明白。多启动几个实例,要看哪方面呢?

@zy445566 如果CPU可以自己实现负载均衡的话,那么node单线程就完全没有啥缺点了,那么其他语言开多线程是不是也没啥优势了呢?

@jyk0011 单线程和多线程还是不一样的,如果cpu多核的话,多线程可以并行处理,如果cpu单核,单线程和多线程其实是一样的。由于cpu时间片很短,所以你使用监控工具看到的现象好像是多线程的感觉,其实同一时间点只有一个cpu核心在运行node线程,所以并不是说的多线程就没啥优势了

@jyk0011 至少根据我的了解你这段代码不可能是因为V8自己开线程也不可能是node自己开辅助线程。 第二负载有很多策略限制,如果因为单线程就全负载了,那多任务还怎么玩。目前我觉得靠谱一点的方向可能是就是系统或CPU。 所以我才说可以尝试一下,我之前用JAVA开跑过多线程,逻辑CPU的利用率封住100%,而不是55%。所以我才考虑是不是负载的原因。


刚看到一篇文章讲Linux的CPU负载均衡策略:https://blog.csdn.net/wh8_2011/article/details/52592359

如果你要测试,你可以先测试是否是CPU或系统,就换个语言用单线程跑会不会负载,排除node或v8。如果看是否是系统相关,你可以早期版本系统和最新做比较。剩下也只有CPU了

@zy445566 谢谢,我估计也是CPU自己做了多核的负载均衡。只是不想多研究了,现在是Windows环境做开发,以后正式上线还不知道啥环境啥CPU呢。我还是先研究其他的吧。 最后想了两天,多线程的优势在于,可以抢到更多的资源,node在跑死循环的时候,并没有把所有的CPU资源都弄过来,还有很多空闲。 这几行代码也不涉及数据库、文件操作,应该不存在其他瓶颈问题。

@zhangmingfeng 我觉得多线程的优势是可以争取更多的资源,如果单线程可以抢十份的话,那么多线程至少能抢十五份。 另外就是单个用户的反应时间。单线程就好像只有一个窗口可以买票,如果前面的人特别墨迹,那么后面的人只能死等。 但是多线程就是有多个窗口可以买票,一个窗口卡住了,可以去其他窗口买票。 你说的CPU时间片也考虑过,只是没想到你说的这种情况,第一个时间片给第一个核,第二个时间片给第二个核,这样多轮循环下来就是多个核心都被利用起来了。

事件驱动、非阻塞式 I/O 模型。楼主可以了解下 unix Io 模型。node.js 的优势主要是非阻塞的 io 模型。node.js 的异步 api 一般都涉及 i/o 操作,js 主线程在运行一段代码的时候,从上往下运行,诸如 var t2 = (new Date()).getTime() - star 这样的同步代码都是由主线程去执行的,当运行到异步代码(io操作、请求数据库、发起http请求、异步操作文件)时,v8开启新的 io 线程来处理 io,js主线程跳过刚刚的异步代码,继续执行下面的代码。Node.js 处理高并发的优势也主要来源于此,因为web中,响应最大的消耗主要来源于 http 的耗时。

@guojingkang LZ的代码没有 iO 操作,其它 CPU 利用率也上涨了

@liangtongzhuo 这个就涉及操作系统了吧

打印不都是io吗

@guojingkang 谢谢,目前还是一直在window环境下。 我现在不确定的是,当主线程里面有多个IO操作的时候,v8会开启几个新的线程来处理? 1、只开启一个新的线程,多个IO操作(文件读写)排队依次进行。 2、开启多个新的线程,一个IO操作(文件读写)对应一个线程。 不确定是哪张情况。

如果是请求数据库的话,应该是看数据库是否是多线程的,比如mysql,似乎是多线程的。

image.png

感觉是和操作系统相关了,在Ubuntu 16.04下使用pidstat命令查看,可以发现是在交替占用CPU的,很有可能因为这些性能查看的指标是一段时间间隔内的平均值,所以会看到每个 CPU都被占用了.

@jyk0011 理论上来说是一个 io 开一个线程,如果只开一个线程来处理 io,其实还是阻塞的。另外请求数据库,其实本质还是网络 io,服务器向数据库服务器发起请求,传送一条指令,数据库服务器执行指令,返回给服务器。所以,web 开发,除了一些比较消耗机器性能的计算操作,大部分都是网络 io。

@zuohuadong 英语没及格过。所以基本看不懂。

@linyimin-bupt 谢谢,我也觉得是系统做了“负载均衡”,或者是cpu自己对对核心做了“负载均衡”。 虽然node是单线程的,但是系统或者CPU把任务分给了多个核心,依次完成的。整体看来就是每个核心都在工作,没有空闲的核心。

首先你要理解nodejs 是libuv的应用(事件驱动的I/O库),而libuv在linux下和windows下实现是不同的,linux 是epoll 模型的实现,windows 是iocp模型的实现,它们之间是不同的,以上各位说的都是epoll 模型下的,都是对的,但是在iocp模式下,就不一定了,iocp模式下是负责IO操作的,而epoll则不负责。iocp会自己建立一个线程池,大概是cpu核数的2倍,所进行的请求处理会唤醒线程池的线程进行cpu操作,进行最大化利用cpu的,而这个是由iocp控制的,有兴趣的话可以阅读windows的iocp相关源代码。

@cnlile 贴了一张图片,就没写自己是啥环境。看了还是要先写好环境的。谢谢回复。 我的这段代码也涉及IO操作吗?

@jyk0011 多线程的一个优势是同一进程下资源为所有线程共享,当然负面影响是必须考虑资源竞争(比如锁)。 详细可以谷歌

回到顶部