news 2026/7/16 21:27:39

Go09-并发编程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Go09-并发编程

第8章:并发编程

8.1 并发基础

Go 使用 goroutine 和 channel 实现并发,这是 Go 最强大的特性之一。

Goroutine

Goroutine 是轻量级线程,由 Go 运行时管理:

packagemainimport("fmt""time")funcsayHello(namestring){fori:=0;i<5;i++{fmt.Printf("Hello, %s! (%d)\n",name,i)time.Sleep(100*time.Millisecond)}}funcmain(){// 启动 goroutinegosayHello("张三")gosayHello("李四")// 主 goroutine 等待time.Sleep(1*time.Second)fmt.Println("主程序结束")}

启动多个 Goroutine

funcmain(){// 启动多个 goroutinefori:=0;i<10;i++{gofunc(nint){fmt.Printf("goroutine %d\n",n)}(i)// 注意:传递参数避免闭包问题}time.Sleep(time.Second)}

8.2 Channel

Channel 是 goroutine 之间通信的管道。

基本 Channel

// 创建 channelch:=make(chanint)// 发送数据gofunc(){ch<-42// 发送}()// 接收数据value:=<-ch// 接收fmt.Println(value)// 42// 关闭 channelclose(ch)

带缓冲的 Channel

// 无缓冲 channel(同步)ch1:=make(chanint)// 带缓冲 channel(异步)ch2:=make(chanint,10)// 缓冲区大小为 10// 发送数据(不阻塞,直到缓冲区满)ch2<-1ch2<-2// 接收数据fmt.Println(<-ch2)// 1fmt.Println(<-ch2)// 2

Channel 方向

// 只发送 channelfuncproducer(chchan<-int){fori:=0;i<10;i++{ch<-i}close(ch)}// 只接收 channelfuncconsumer(ch<-chanint){forv:=rangech{fmt.Println(v)}}funcmain(){ch:=make(chanint)goproducer(ch)consumer(ch)}

8.3 Channel 操作

Select 语句

// 同时监听多个 channelfuncmain(){ch1:=make(chanstring)ch2:=make(chanstring)gofunc(){time.Sleep(1*time.Second)ch1<-"来自 channel 1"}()gofunc(){time.Sleep(2*time.Second)ch2<-"来自 channel 2"}()// select 等待第一个完成的 channelselect{casemsg:=<-ch1:fmt.Println(msg)casemsg:=<-ch2:fmt.Println(msg)case<-time.After(3*time.Second):fmt.Println("超时")}}

超时控制

funcfetchData()(string,error){ch:=make(chanstring,1)gofunc(){// 模拟耗时操作time.Sleep(2*time.Second)ch<-"数据"}()select{caseresult:=<-ch:returnresult,nilcase<-time.After(1*time.Second):return"",errors.New("请求超时")}}

非阻塞操作

select{casemsg:=<-ch:fmt.Println("收到消息:",msg)default:fmt.Println("没有消息")}

8.4 同步原语

sync.WaitGroup

packagemainimport("fmt""sync")funcmain(){varwg sync.WaitGroupfori:=0;i<10;i++{wg.Add(1)// 增加计数器gofunc(nint){deferwg.Done()// 减少计数器fmt.Printf("goroutine %d\n",n)}(i)}wg.Wait()// 等待所有 goroutine 完成fmt.Println("所有 goroutine 完成")}

sync.Mutex

packagemainimport("fmt""sync")typeCounterstruct{mu sync.Mutex valueint}func(c*Counter)Increment(){c.mu.Lock()// 加锁deferc.mu.Unlock()// 解锁c.value++}func(c*Counter)Value()int{c.mu.Lock()deferc.mu.Unlock()returnc.value}funcmain(){counter:=&Counter{}varwg sync.WaitGroupfori:=0;i<1000;i++{wg.Add(1)gofunc(){deferwg.Done()counter.Increment()}()}wg.Wait()fmt.Println("最终值:",counter.Value())// 1000}

sync.RWMutex(读写锁)

typeCachestruct{mu sync.RWMutex itemsmap[string]string}func(c*Cache)Get(keystring)(string,bool){c.mu.RLock()// 读锁deferc.mu.RUnlock()value,ok:=c.items[key]returnvalue,ok}func(c*Cache)Set(key,valuestring){c.mu.Lock()// 写锁deferc.mu.Unlock()c.items[key]=value}

sync.Once

typeSingletonstruct{instanceinterface{}once sync.Once}func(s*Singleton)Get()interface{}{s.once.Do(func(){s.instance=createInstance()})returns.instance}

sync.Map

packagemainimport("fmt""sync")funcmain(){varm sync.Map// 存储m.Store("key1","value1")m.Store("key2","value2")// 读取ifvalue,ok:=m.Load("key1");ok{fmt.Println(value)}// 遍历m.Range(func(key,valueinterface{})bool{fmt.Printf("%v: %v\n",key,value)returntrue// 返回 false 停止遍历})}

8.5 并发模式

Worker Pool

funcworker(idint,jobs<-chanint,resultschan<-int){forjob:=rangejobs{fmt.Printf("worker %d 处理 job %d\n",id,job)time.Sleep(time.Second)results<-job*2}}funcmain(){jobs:=make(chanint,100)results:=make(chanint,100)// 启动 workersforw:=1;w<=3;w++{goworker(w,jobs,results)}// 发送 jobsforj:=1;j<=9;j++{jobs<-j}close(jobs)// 收集结果fora:=1;a<=9;a++{fmt.Println("结果:",<-results)}}

Fan-out / Fan-in

// Fan-out: 多个 worker 读取同一个 channel// Fan-in: 多个 worker 写入同一个 channelfuncfanOut(input<-chanint,workersint)[]<-chanint{channels:=make([]<-chanint,workers)fori:=0;i<workers;i++{channels[i]=process(input)}returnchannels}funcfanIn(channels...<-chanint)<-chanint{varwg sync.WaitGroup merged:=make(chanint)for_,ch:=rangechannels{wg.Add(1)gofunc(c<-chanint){deferwg.Done()forv:=rangec{merged<-v}}(ch)}gofunc(){wg.Wait()close(merged)}()returnmerged}

Pipeline

funcgenerate(nums...int)<-chanint{out:=make(chanint)gofunc(){for_,n:=rangenums{out<-n}close(out)}()returnout}funcsquare(in<-chanint)<-chanint{out:=make(chanint)gofunc(){forn:=rangein{out<-n*n}close(out)}()returnout}funcmain(){// Pipeline: generate -> squareforv:=rangesquare(generate(1,2,3,4,5)){fmt.Println(v)// 1, 4, 9, 16, 25}}

8.6 练习

  1. 实现一个简单的并发爬虫
  2. 使用 Worker Pool 模式处理批量任务
  3. 实现一个并发安全的缓存
  4. 编写一个 Pipeline 处理数据流

8.7 下一章

下一章我们将学习 Go 语言的标准库精讲。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 21:27:34

轨道交通信号系统的“神经末梢”——应答器技术深度解析

1. 应答器&#xff1a;轨道交通的“神经末梢”如何工作&#xff1f; 想象一下&#xff0c;当你开车经过一个陌生的路口时&#xff0c;导航会突然提醒你“前方限速60公里”。在轨道交通系统中&#xff0c;应答器就是扮演这种“实时路况播报员”的角色。不过它的本事可不止于此—…

作者头像 李华
网站建设 2026/7/16 21:26:11

Kubernetes源码编译安装最佳实践:Ubuntu 24.04 + k8s v1.28.8

1. 项目概述&#xff1a;这不是一次“装个软件”&#xff0c;而是一场对Kubernetes底层逻辑的系统性校准 “k8s编译安装最佳实践”——这八个字在2024年已经不是新手入门的模糊指引&#xff0c;而是资深运维、平台工程师甚至SRE团队在交付关键生产环境前必须亲手完成的一道“准…

作者头像 李华
网站建设 2026/7/16 21:23:32

从零到一:在Mac上为VSCode构建高效的C++开发与调试环境

1. 环境准备与基础配置在Mac上搭建C开发环境的第一步是确保系统具备必要的工具链。打开终端输入xcode-select --install安装Xcode命令行工具&#xff0c;这会自动配置Clang编译器和相关依赖。验证安装是否成功可以运行clang --version&#xff0c;正常情况会显示类似这样的信息…

作者头像 李华
网站建设 2026/7/16 21:23:21

电源工程师必备电路设计与应用指南

1. 电源工程师必备电路解析作为一名从业十余年的电源工程师&#xff0c;我深知电路设计是电源系统的核心。今天我将分享电源工程师必须掌握的几类关键电路&#xff0c;这些电路构成了电源设计的基础框架。电源电路主要分为以下几大类&#xff1a;整流滤波电路&#xff1a;将交流…

作者头像 李华
网站建设 2026/7/16 21:21:38

基于C++的高性能就业数据分析平台:架构设计与工程实践

1. 项目概述与核心价值最近几年&#xff0c;每到毕业季&#xff0c;总能听到身边学弟学妹们关于就业的焦虑&#xff1a;投出去的简历石沉大海&#xff0c;不知道自己的专业在市场上到底值多少钱&#xff0c;更不清楚哪些城市、哪些行业才是真正的“蓝海”。作为过来人&#xff…

作者头像 李华