Golang并发编程

几个概念 并行和并发 并行 多线程程序在多个核的cpu上运行,就是并行 并发 多线程程序在一个核的cpu上运行,就是并发 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。比如你运行一个 Go 程序 go run main.go,操作系统就会创建一个进程。每个进程有自己独立的内存空间、文件描述符、环境变量等,不同进程之间的资源默认是隔离的。 B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。多个线程共享所属进程的所有资源(内存、文件句柄等) C.一个进程可以创建和撤销多个线程;同一个进程中的多个线程之间可以并发执行。 协程和线程 协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度也是自己实现的。 线程:一个线程上可以跑多个协程,协程是轻量级的线程。 Goroutine 启动单个goroutine goroutine的概念类似于线程,但 goroutine是由Go的运行时(runtime)调度和管理的。Go程序会智能地将 goroutine 中的任务合理地分配给每个CPU。Go语言之所以被称为现代化的编程语言,就是因为它在语言层面已经内置了调度和上下文切换的机制。 启动goroutine的方式非常简单,只需要在调用的函数(普通函数和匿名函数)前面加上一个go关键字。 1func hello() { 2 fmt.Println("Hello Goroutine!") 3} 4func main() { 5 go hello() 6 fmt.Println("main goroutine done!") 7 time.sleep(time.Second) 8} 执行上面的代码你会发现,这一次先打印main goroutine done!,然后紧接着打印Hello Goroutine!。 启动多个goroutine 1var wg sync.WaitGroup 2 3func hello(i int) { 4 defer wg.Done() // goroutine结束就登记-1 5 fmt.Println("Hello Goroutine!", i) 6} 7func main() { 8 9 for i := 0; i < 10; i++ { 10 wg.Add(1) // 启动一个goroutine就登记+1 11 go hello(i) 12 } 13 wg.Wait() // 等待所有登记的goroutine都结束 14} 若主协程退出,其他任务被迫终止。没有主协程,新协程也不进行。 ...

April 24, 2026 · 5 min · 1006 words · Jamaisvu

Golang八股文

本文持续更新 堆、栈 它们是程序运行时,两块用途完全不同的内存区域。 栈(Stack)—— 函数的临时小抽屉 每个函数运行时,都会在栈上占一小块空间; 函数里的局部变量、参数默认都往栈上放; 函数一结束,栈空间自动清空,变量直接销毁; 速度极快,几乎零开销; 不需要 GC 垃圾回收。 特点:自动申请、自动释放,快、小、临时。 堆(Heap)—— 全局公共大仓库 一块共享的大内存; 放那些函数结束后还需要活着的变量; 不会自动销毁,靠 Go 的 GC 来回收; 分配慢、寻址慢、有 GC 开销。 特点:手动 / 编译器决定分配,GC 回收,慢、大、持久。 在栈还是堆 直接用 Go 自带的逃逸分析命令看: 1go build -gcflags="-m" main.go 输出里会出现两种关键行: does not escape → 变量在 栈 上 escapes to heap → 变量逃逸到 堆 上 slice 数据结构 slice是引用类型,共享内存地址 切片扩容 只有append才会触发扩容!手动make只是新建切片。 扩容会彻底替换底层数组: 计算新的容量(按增长规则) 在堆上新建一个更大的底层数组 把旧数组的所有数据完整拷贝到新数组 切片指针指向新数组,更新 len/cap 旧数组如果没有其他引用,会被 GC 自动回收 容量增长规则(Go 1.18+ 最新版) 小切片快速扩容,大切片平缓扩容,避免内存浪费 ...

April 22, 2026 · 5 min · 1000 words · Jamaisvu