九:goroutine(1.什么是协程)

goroutine

这是Go最大的特点。

必须掌握:

  • goroutine
  • channel
  • select
  • sync.WaitGroup
  • Mutex
  • RWMutex
  • Once
  • Cond
  • atomic

按照下面顺序系统学习:

yaml 复制代码
1. 并发基础概念
        |
        v
2. goroutine(轻量级线程)
        |
        v
3. channel(通信机制)
        |
        v
4. select(多路复用)
        |
        v
5. sync.WaitGroup(等待任务完成)
        |
        v
6. Mutex / RWMutex(共享内存同步)
        |
        v
7. Once(只执行一次)
        |
        v
8. Cond(条件变量)
        |
        v
9. atomic(无锁原子操作)

一、Go 并发设计思想

先理解一句 Go 的哲学:

不要通过共享内存来通信,而应该通过通信来共享内存。

英文:

vbnet 复制代码
Don't communicate by sharing memory;
share memory by communicating.

这句话非常重要。

java传统模型

多个线程访问同一块内存:

count++;

需要:

arduino 复制代码
synchronized
Lock
volatile
AtomicInteger

这叫:

数据竞争(Data Race)

Go 更推荐:

css 复制代码
goroutine A

      |
      |
   channel
      |
      |
goroutine B

数据通过 channel 流动。

二、goroutine

Java Thread

操作系统线程:

markdown 复制代码
Java Thread

      |
      |
 OS Thread

      |
      |
 CPU Core

线程由 OS 调度。

创建成本:

makefile 复制代码
线程栈:
1MB左右

10万个线程:

复制代码
100GB内存

几乎不可行。

Go goroutine:这部分详细请看本专栏的GMP详解

结构:

markdown 复制代码
goroutine

    |
    |
 Go Runtime Scheduler

    |
    |
 OS Thread

    |
    |
 CPU

Go 自己实现调度。

叫:

GMP 调度模型

三、创建 goroutine

最简单:

go 复制代码
package main

import (
    "fmt"
    "time"
)

func hello(){

    fmt.Println("hello")

}


func main(){

    go hello()

    time.Sleep(time.Second)

}

关键:

scss 复制代码
go hello()

表示:

创建一个新的 goroutine。


执行流程:

main goroutine:

yaml 复制代码
main

 |
 |
 创建

 |
 v

hello goroutine

两个并发执行。

四、goroutine 生命周期

非常重要。

例如:

go 复制代码
func main(){

    go func(){

        fmt.Println("hello")

    }()

}

运行:

css 复制代码
main结束

↓

整个程序退出

↓

所有goroutine结束

所以:

输出:

可能:

复制代码
什么都没有

因为:

goroutine还没有运行。

所以要有主次之分,生产环境中,我们常用WaitGroup,让主协程来管理所有的goroutine

五、goroutine 调度

Go不是:

复制代码
一个goroutine对应一个线程

而是:

markdown 复制代码
100万个goroutine

        |
        |
      scheduler

        |
        |
    几个线程执行

例如:

服务器:

复制代码
10000请求

↓

10000 goroutine

↓

几十个线程

所以 Go 非常适合:

  • 网络服务
  • RPC
  • 微服务
  • IO密集任务

六、goroutine 常见问题

1. goroutine泄漏

例如:

go 复制代码
func worker(ch chan int){

    for{

        data:=<-ch

        fmt.Println(data)

    }

}

如果:

没人发送:

复制代码
worker永久阻塞

goroutine泄漏。


生产环境:

必须考虑:

复制代码
退出机制

通常:

context。

2. 闭包变量捕获问题

经典:

错误:

css 复制代码
for i:=0;i<10;i++{

    go func(){

        fmt.Println(i)

    }()

}

输出:

可能:

erlang 复制代码
10
10
10
...

原因:

所有goroutine共享:

css 复制代码
同一个i地址

正确:

css 复制代码
for i:=0;i<10;i++{

    i:=i

    go func(){

        fmt.Println(i)

    }()

}

或者:

css 复制代码
for i:=0;i<10;i++{

    go func(n int){

        fmt.Println(n)

    }(i)

}

7、面试重点

问题一:为什么 goroutine 比线程轻?

回答:

goroutine 由 Go runtime 管理,采用 GMP 的 M:N 调度模型,不需要一个 goroutine 对应一个 OS Thread;同时 goroutine 初始栈很小,而且栈可以动态扩缩容。因此相比传统 OS Thread,goroutine 的创建和调度成本更低,可以支持大量并发 goroutine。

问题二:goroutine 什么时候切换?

回答:

goroutine 在阻塞或者被调度器抢占时会发生调度切换。常见情况包括系统调用、channel 阻塞、网络 IO、定时器等待,以及 Go runtime 的抢占式调度。

相关推荐
ZhengEnCi4 小时前
模型训练完整流程:从数据准备到模型上线的 10 个关键步骤(全文可跑)
后端·算法
王中阳Go4 小时前
后端转 Agent 岗面试怎么答:8 个高频问题与应答口径
人工智能·后端·python·大语言模型
程序猿DD4 小时前
OctaFuse Gateway 2.18.0:MCP 接入支持 OAuth,供应商粘性绑定可视化管理
后端
ZhengEnCi6 小时前
Agent 规则管理:让 Memory 做索引、让 Skill 存规则——上下文上限实测与分工方案
后端
nice_lcj5206 小时前
深入理解 Java 反射:从 Class 对象到方法调用(含性能实测 + 迷你 IOC 实战 + 面试考点)
java·开发语言·后端·面试
骑着蜗牛撵大象3277 小时前
2026 后端 AI 工程化:Spring AI 管调用、MCP 管工具、Agent 内嵌管自治
java·人工智能·后端·spring·ai·可观测性·mcp
摸爬滚打的小李7 小时前
Spring XML + WAR + Tomcat 项目启动
后端
IT_陈寒8 小时前
SpringBoot自动配置的坑,这次终于爬出来了
前端·人工智能·后端
RainbowFish9 小时前
# RAG 与智能体记忆:从原理到工程实践 > 一篇给学习者的总结。
后端
苏三说技术9 小时前
为什么越来越多人用Arthas 4 ?
后端