当前位置: 首页 > news >正文

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 语言的标准库精讲。

http://www.cnnetsun.cn/news/3436941.html

相关文章:

  • 轨道交通信号系统的“神经末梢”——应答器技术深度解析
  • 如何快速上手Upscayl:免费开源AI图像放大工具的终极实用指南
  • Kubernetes源码编译安装最佳实践:Ubuntu 24.04 + k8s v1.28.8
  • 从零到一:在Mac上为VSCode构建高效的C++开发与调试环境
  • 电源工程师必备电路设计与应用指南
  • 基于C++的高性能就业数据分析平台:架构设计与工程实践
  • 基于YOLOv8的扑克牌识别系统开发实践
  • QMCFLAC2MP3终极指南:3步解锁QQ音乐加密文件,实现全平台自由播放
  • 2026年企业级Agent OS深度评测与选型指南:图智能如何重构智能体架构
  • Flutter---RefreshIndicator案例
  • Awesome-MCP-Servers与Claude Desktop集成:如何配置6000+服务器扩展AI助手
  • 无线电流检测技术:高压侧浮空测量方案解析
  • Spring 中 配置文件 加入 aspectj-autoproxy 项目报错
  • LightTrack视频处理教程:3步实现任意视频的人体姿态追踪
  • 复杂场景音画同步实测:多人抢话快剪辑谁家AI扛得住
  • 上下拉电阻取值实战:从电路原理到工程计算的完整指南
  • 原子服务卡片多尺寸渲染优化:增量重绘消除切换闪烁技巧
  • cann/asc-devkit half转int4x2 SIMD指令
  • swift-create-xcframework安全最佳实践:确保二进制框架的完整性与可靠性
  • HarmonyOS7 并发模型:TaskPool vs Worker 怎么选
  • 现代C:标准库:如何使用互斥量等技术协调线程运行?
  • 3分钟学会:如何将B站缓存m4s视频转换为MP4格式
  • Cervus部署最佳实践:生产环境中的内核模块配置与监控
  • 免费知识管理系统Knowledge:企业级知识库搭建终极指南
  • Linux服务器搭建
  • MPL_ROS社区案例研究:实际机器人项目中的应用经验与问题解决方案
  • ssm 基于云的学习笔记系统设计与开发
  • CANN/asc-devkit矢量与运算API文档
  • 仅用六分钟,黑客借助Gemini CLI自主构建并迁移CC僵尸网络
  • Invoke-WCMDump安全审计指南:如何检测和防御凭据泄露风险