进程,线程和协程
本文主要讲go中的进程,线程和协程和其基础面试八股
一、概念
1.进程
定义:操作系统分配资源(CPU、内存、磁盘 IO 等)的基本单位,是程序的一次运行实例。
特点:
- 进程之间相互独立,有自己的独立内存空间,通信需要借助 IPC(管道、消息队列、套接字等)。
- 开销大:创建 / 销毁、切换进程需要操作系统内核参与,消耗大量资源。
- 示例:你打开的一个 Go 程序、一个浏览器窗口,都是一个进程。
2.线程
定义:操作系统调度执行的基本单位,隶属于进程,一个进程可以包含多个线程。
特点:
- 线程共享所属进程的内存空间(代码段、数据段、堆),但有自己的栈空间。
- 开销中等:比进程小,但线程切换仍需内核态 / 用户态切换,消耗一定资源。
- 示例:浏览器的一个标签页可能对应一个线程,Go 程序运行时的
runtime也会启动多个线程。
3.协程(Goroutine)
定义:Go 语言层面实现的轻量级 “线程”,由 Go 运行时(runtime)调度,而非操作系统内核。
核心特点:
- 轻量级:初始栈大小仅 2KB,可动态扩容(最大几 MB),一台机器可轻松创建十万级 Goroutine。
- 调度成本低:Goroutine 切换在用户态完成,无需内核参与,切换耗时仅为线程的 1/100 左右。
- 由 Go runtime 管理:runtime 会将多个 Goroutine 映射到少量操作系统线程上执行,实现 GMP。
- 语法简单:通过
go 函数名()即可创建。
二、对比与关系

通俗一点来讲解一下三者关系:运行一个go程序,操作系统会创建一个进程,这个进程是 Go 程序的运行载体。进程启动后,运行时会初始化一组操作系统线程,是操作系统内核直接调度的实体,也就是代码执行者。goroutine需要依附在线程上,一个线程可以有多个goroutine,是轻量级执行体。
用一句话概括的话:进程管资源,线程管内核调度,Goroutine 管 Go 程序的轻量级执行。
三、考点
1.Goroutine 和操作系统线程的核心区别是什么?
Goroutine 是 Go 运行时管理的轻量级执行体,和操作系统线程的核心区别有 5 点:
- 调度主体:线程由操作系统内核调度(内核态切换),Goroutine 由 Go runtime 在用户态调度,切换成本仅为线程的 1/10 左右;
- 资源开销:线程创建 / 销毁、切换开销大,Goroutine 开销极小,单台机器可创建十万级 Goroutine,而线程仅能创建几千个;
- 栈特性:线程栈是固定大小(MB 级),易溢出;Goroutine 栈初始 2KB,可动态扩容 / 缩容(最大几 MB),更节省内存;
- 阻塞处理:线程阻塞会导致对应内核线程闲置,Goroutine 阻塞时,runtime 会将绑定的 P 切换到其他空闲 M 上,避免线程闲置;
- 通信方式:线程依赖共享内存 + 锁(易出竞态问题),Goroutine 推荐用 Channel 通信(“以通信代替共享内存”),更安全。
2.进程、线程、Goroutine 的层级关系是什么?
- 进程:操作系统分配资源(内存、CPU、文件描述符)的最小单位,是 Go 程序的运行容器,一个 Go 程序对应一个进程;
- 线程:隶属于进程,是操作系统内核调度的最小单位,CPU 真正执行的实体,Go 协程必须依附线程运行;
- Goroutine:隶属于线程,是 Go 运行时调度的最小执行单元,运行在用户态,一个线程可承载多个 Goroutine。
- 记住:进程管资源,线程管内核调度,Goroutine 管 Go 程序的轻量级执行。
3.Go 中创建 Goroutine 的方式是什么?Goroutine 如何退出?
(主要是退出方式,正常,优雅和强制退出,切记goroutine无法强制杀死)
- 创建方式:通过
go 函数名()即可创建,无需手动管理,Go runtime 会自动调度执行; - 退出方式:
- 正常退出:Goroutine 内的函数执行完毕,自动退出;
- 优雅退出:无法主动 “杀死” 一个 Goroutine,需通过 Channel 传递退出信号、Context 控制超时 / 取消,或 sync.WaitGroup 等待完成;
- 强制退出:主 Goroutine 退出后,进程终止,所有子 Goroutine 会被强制终止。
4.GMP调度模型
(这个我目前不打算单独记录一张,具体可以看这位佬的和小林coding)
深入理解GMP模型
小林coding的GMP面试题








