高并发系统,为什么有人用Node.js不用Go

摘要:后端圈子里有个说法:Node.js是单线程的,Go有协程,天生适合高并发。很多人顺着这个逻辑得出结论:高并发就得用Go,Node.js不行。但真实工程里,事情没那么简单。

后端圈子里有个说法:Node.js是单线程的,Go有协程,天生适合高并发。很多人顺着这个逻辑得出结论:高并发就得用Go,Node.js不行。

但真实工程里,事情没那么简单。

今天聊聊,在实际项目里,Node.js和Go到底谁更能扛并发。


一个厨师和一个厨师团队的区别

先打个比方。

Node.js像一个特别麻利的厨师,一个人盯着十个锅,反应飞快,但始终只有一双手在操作。

Go像一整个厨师团队,每个人独立干活,多个灶同时开火。

最后结果可能差不多,菜都能按时端上来。但背后的干活方式完全不一样。


Node.js:单线程,但不傻等

Node.js的核心叫事件循环。它的工作方式是:你先去干活,干完叫我,我先处理别的事。

看段代码:

console.log("开始");

setTimeout(() => {
   console.log("2秒后执行");
}, 2000);

console.log("结束");

// 输出:
// 开始
// 结束
// 2秒后执行

关键点在哪?Node.js没有在那干等两秒。它把setTimeout这个任务挂起来,转身就去干别的事了。两秒后回来执行。

这种机制在面对网络请求、数据库查询、文件读写这类I/O任务时特别高效。因为等待的时间不浪费CPU,一个线程就能服务大量连接。


Go:协程,真的同时在干活

Go的并发靠的是Goroutine。看代码:

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("开始")
    
    go func() {
        time.Sleep(2 * time.Second)
        fmt.Println("2秒后执行")
    }()
    
    fmt.Println("结束")
    time.Sleep(3 * time.Second)
}

// 输出:
// 开始
// 结束
// 2秒后执行

这个"go"关键字的意思是:开个新协程,交给调度器,分配到不同的CPU核心去跑。如果你有4核CPU,真的可以四个任务同时跑,不是切来切去,是物理意义上的并行。


并发和并行,很多人搞混

这是Node.js和Go最根本的区别。

Node.js是并发。像一个厨师在多个锅之间来回跑,同一时间只做一件事,但切换极快。适合等别人回应的任务。

Go是并行。像多个厨师同时炒菜,多件事真的同时发生。适合需要计算的任务。


真正拉开差距的地方:CPU密集型任务

什么场景Go完胜?图片压缩、视频转码、加密解密、大量数学计算这些CPU密集型的活。

Node.js单线程,一旦开始算,整个服务就卡住了,新请求进不来。就像厨师在切一块牛排,其他菜全停了。

Go把任务分到多个核心,算法不会堵住服务,还能继续接新请求。就像一个人在炒菜,另一个人在切菜,互不影响。


I/O场景,两者差不多

但API网关、数据库访问、调第三方接口这类场景,瓶颈在网络、磁盘、数据库,不在CPU。这时候Node.js的事件循环和Go的协程调度,效果很接近。

所以现实里你会看到,大量Web API用Node写,大量微服务用Go写,都没问题。


内存占用有差别

Node.js每个挂起的异步操作占的内存很小,就是一个回调函数。

Go每个Goroutine大约占2KB内存。虽然已经很小了,但在处理极大规模连接时,Node.js会稍微占点优势。


到底怎么选

直接对照着看:

想快速搭个API,做简单的增删改查,用Node.js。开发快,生态多。

做实时聊天、高频I/O,两者都能轻松处理成千上万的连接。

做图像视频处理、加密计算,用Go。能利用多核并行,不堵服务。

搭大型复杂系统、微服务,用Go。强类型,内置并发,好维护。


一句话总结

Node.js赢在开发速度和I/O并发。Go赢在多核并行和稳定上限。

你现在的项目,是需要一个快手厨师,还是一个特级厨师团队?想清楚这个,就知道该用谁了。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://shenqiku.cn/article/FLY_13385