goroutine 是 Go 实现的轻量级用户态执行单元,线程是操作系统内核实现的重型执行单元。Go 协程比线程轻量成千上万倍。

Go 高并发的核心秘密 = 轻量级 goroutine + 高效 GMP 调度

Go M-P-G 调度模型(M 线程、P 逻辑处理器、G goroutine):goroutine 先入全局 / 本地运行队列,由 P 绑定 M(系统线程),再由go 运行时(runtime)调度执行

一、整理 goroutine 和线程的核心区别:

  1. 轻量级:goroutine 初始栈 2KB,线程 1MB,资源消耗差几百倍;
  2. 调度成本低:协程切换在用户态完成,比线程切换快 10~100 倍;
  3. 数量级不同:单机可轻松创建百万级 goroutine,线程只能上千;
  4. 调度器不同:线程由内核调度,goroutine 由 Go GMP 调度器管理;
  5. 通信模型更安全:goroutine 推荐 channel 通信,线程用共享内存 + 锁。

二、Go的并发模型

Go的并发模型,通过 goroutine 和 channel 来实现并发:

  • goroutine:协程,是 Go 语言轻量级的线程,由 Go 运行时管理,其栈内存可以动态伸缩,初始时仅需 2KB,创建和销毁的开销极小。
  • channel:用于在 goroutine 之间进行通信和同步,保证数据的安全传递。

三、和传统线程相比,主要区别

1、创建和销毁

  • Goroutine‌:由Go语言的运行时系统创建和销毁,创建开销小,可以在Go应用程序中创建大量的Goroutine而不会显著影响性能‌。用户态操作,极快。
  • 线程‌:由操作系统创建和销毁,创建开销较大,每次创建和销毁都需要操作系统的支持‌。内核态操作,慢、重。

2. 切换开销(最重要性能点)

  • 线程切换:需要用户态 ↔ 内核态切换,保存大量寄存器,耗 CPU、耗时间
  • goroutine 切换完全在用户态完成,只保存少量上下文,速度比线程快 10~100 倍。

3、调度机制

  • ‌Goroutine‌:由Go语言的运行时(GMP 调度器)调度,采用非抢占式调度,通过协作完成任务切换,调度效率高‌。(协作式 + 抢占式结合)
  • ‌线程‌:由OS操作系统内核调度,采用抢占式调度,执行顺序由操作系统决定,调度效率相对较低。

4、资源消耗

一台机器能轻松跑上百万 goroutine,但线程最多几千个。

  • ‌Goroutine‌:内存开销小 ,每个Goroutine的栈空间是动态增长的,初始栈空间通常只有几KB‌(2KB),可自动伸缩(最大 GB 级)。切换开销小,因为Goroutine的切换是在用户态完成的,不需要进行内核态和用户态的切换‌。
  • ‌线程‌:每个线程有自己的栈空间和寄存器集合,栈空间通常是固定分配的,通常为几MB,默认栈大小 1MB~8MB。不敢开太多,切换开销大,因为线程的切换涉及到操作系统的调度和上下文切换。

5、通信方式

  • ‌Goroutine‌:通过通道(channel)进行通信和同步,这种方式更加安全、方便和高效,避免了复杂的同步机制带来的问题‌。(不要通过共享内存来通信,要通过通信来共享内存
  • ‌线程‌:可以通过共享内存或消息队列进行通信,需要使用复杂的同步机制(如互斥锁、条件变量等)来避免竞争条件和死锁等问题‌。容易死锁、难写。

6. 数量关系

  • OS 线程:M 个
  • goroutine:N 个      👉 N:M 映射调度(很多协程跑在少数线程上)

四、超级通俗类比

  • 线程 = 独立办公室占空间大、成本高、不能开太多

  • goroutine = 工位占空间极小、随时增减、可以开一大堆

  • 线程切换 = 换办公室要搬家、要登记、很慢

  • goroutine 切换 = 换工位干活瞬间切换、几乎零成本

    Logo

    AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

    更多推荐