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

Go语言八股之并发详解

   💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。



非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨
 

前言

小郑最近在准备Go语言的面试题,通过github和b站等各种学习网站上学习go语言的八股文,并且整理出自己觉得面试可能会问到的知识点,希望通过做笔记的方式来巩固自己的知识点,并且也希望可以帮助到大家在面试的时候更加得心应手一些,那么从现在开始,和我一起加入八股学习之旅吧!

1.Go 中主协程如何等待其余协程退出?

答:Go 的 sync.WaitGroup 是等待一组协程结束,sync.WaitGroup 只有 3 个方法,Add()是添加计数,Done()减去一个计数,Wait()阻塞直到所有的任务完成。Go 里面还能通过有缓冲的 channel 实现其阻塞等待一组协程结束,这个不能保证一组 goroutine 按照顺序执行,可以并发执行协程。Go 里面能通过无缓冲的 channel 实现其阻塞等待一组协程结束,这个能保证一组 goroutine 按照顺序执行,但是不能并发执行。

Add(n int):设置需要等待的协程数量。通常在启动协程之前调用,传入一个整数,表示需要等待的协程数量。

Done():每个协程完成时调用,通常在协程的最后,减少等待的计数。

Wait():主协程通过调用 Wait() 来阻塞,直到计数器减少到零,表示所有协程都完成。

2.多个 goroutine 对同一个 map 写会 panic,异常是否可以用 defer 捕获?

可以捕获异常,但是只能捕获一次,Go语言,可以使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,才使用Go中引入的Exception处理:defer, panic, recover Go中,对异常处理的原则是:多用error包,少用panic

3.golang实现多并发请求(发送多个get请求)

在go语言中其实有两种方法进行协程之间的通信。一个是共享内存、一个是消息传递
共享内存(互斥锁)

//基本的GET请求
package mainimport ("fmt""io/ioutil""net/http""time""sync""runtime"
)// 计数器
var counter int = 0func httpget(lock *sync.Mutex){lock.Lock()counter++resp, err := http.Get("http://localhost:8000/rest/api/user")if err != nil {fmt.Println(err)return}defer resp.Body.Close()body, err := ioutil.ReadAll(resp.Body)fmt.Println(string(body))fmt.Println(resp.StatusCode)if resp.StatusCode == 200 {fmt.Println("ok")}lock.Unlock()
}func main() {start := time.Now()lock := &sync.Mutex{}for i := 0; i < 800; i++ {go httpget(lock)}for  {lock.Lock()c := counterlock.Unlock()runtime.Gosched()if c >= 800 {break}}end := time.Now()consume := end.Sub(start).Seconds()fmt.Println("程序执行耗时(s):", consume)
}

问题
我们可以看到共享内存的方式是可以做到并发,但是我们需要利用共享变量来进行协程的通信,也就需要使用互斥锁来确保数据安全性,导致代码啰嗦,复杂话,不易维护。我们后续使用go的消息传递方式避免这些问题。
消息传递(管道)

//基本的GET请求
package mainimport ("fmt""io/ioutil""net/http""time"
)
// HTTP get请求
func httpget(ch chan int){resp, err := http.Get("http://localhost:8000/rest/api/user")if err != nil {fmt.Println(err)return}defer resp.Body.Close()body, err := ioutil.ReadAll(resp.Body)fmt.Println(string(body))fmt.Println(resp.StatusCode)if resp.StatusCode == 200 {fmt.Println("ok")}ch <- 1
}
// 主方法
func main() {start := time.Now()// 注意设置缓冲区大小要和开启协程的个人相等chs := make([]chan int, 2000)for i := 0; i < 2000; i++ {chs[i] = make(chan int)go httpget(chs[i])}for _, ch := range chs {<- ch}end := time.Now()consume := end.Sub(start).Seconds()fmt.Println("程序执行耗时(s):", consume)
}

总结:
我们通过go语言的管道channel来实现并发请求,能够解决如何避免传统共享内存实现并发的很多问题而且效率会高于共享内存的方法。

4.sync.pool

<font style="color:rgb(5, 7, 59);">sync.Pool</font> 是 Go 语言在标准库 <font style="color:rgb(5, 7, 59);">sync</font> 包中提供的一个类型,它主要用于存储和复用临时对象,以减少内存分配的开销,提高性能。以下是对 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 的详细解析:

4.1基本概念

<font style="color:rgb(5, 7, 59);">sync.Pool</font> 是一个可以存储任意类型的临时对象的集合。当你需要一个新的对象时,可以先从 <font style="color:#DF2A3F;">sync.Pool</font> 中尝试获取;如果 <font style="color:#DF2A3F;">sync.Pool</font> 中有可用的对象,则直接返回该对象;如果没有,则需要自行创建。使用完对象后,可以将其放回 <font style="color:#DF2A3F;">sync.Pool</font> 中,以供后续再次使用。

4.2主要特点
  1. 减少内存分配和垃圾回收(GC)压力:通过复用已经分配的对象,<font style="color:rgb(5, 7, 59);">sync.Pool</font> 可以显著减少内存分配的次数,从而减轻 GC 的压力,提高程序的性能。
  2. 并发安全<font style="color:rgb(5, 7, 59);">sync.Pool</font> 是 Goroutine 并发安全的,多个 Goroutine 可以同时从 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 中获取和放回对象,而无需额外的同步措施。
  3. 自动清理:Go 的垃圾回收器在每次垃圾回收时,都会清除 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 中的所有对象。因此,你不能假设一个对象被放入 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 后就会一直存在。
4.3使用场景

<font style="color:rgb(5, 7, 59);">sync.Pool</font> 适用于以下场景:

  • 对象实例创建开销较大的场景,如数据库连接、大型数据结构等。
  • 需要频繁创建和销毁临时对象的场景,如 HTTP 处理函数中频繁创建和销毁的请求上下文对象。
4.4使用方法
  1. 创建 Pool 实例:首先,你需要创建一个 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 的实例,并配置 <font style="color:rgb(5, 7, 59);">New</font> 方法。<font style="color:rgb(5, 7, 59);">New</font> 方法是一个无参函数,用于在 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 中没有可用对象时创建一个新的对象。
var pool = &sync.Pool{  New: func() interface{} {  return new(YourType) // 替换 YourType 为你的类型  },  
}
  1. 获取对象:使用 <font style="color:rgb(5, 7, 59);">Get</font> 方法从 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 中获取对象。<font style="color:rgb(5, 7, 59);">Get</font> 方法会返回 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 中已经存在的对象(如果存在的话),或者调用 <font style="color:rgb(5, 7, 59);">New</font> 方法创建一个新的对象。

obj := pool.Get().(*YourType) // 替换 YourType 为你的类型,并进行类型断言

  1. 使用对象:获取到对象后,你可以像使用普通对象一样使用它。
  2. 放回对象:使用完对象后,使用 <font style="color:rgb(5, 7, 59);">Put</font> 方法将对象放回 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 中,以供后续再次使用。

pool.Put(obj)

4.5注意事项
  1. 对象状态未知:从 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 中获取的对象的状态是未知的。因此,在使用对象之前,你应该将其重置到适当的初始状态。
  2. 自动清理:由于 Go 的垃圾回收器会清理 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 中的对象,因此你不能依赖 <font style="color:rgb(5, 7, 59);">sync.Pool</font> 来长期存储对象。
  3. 不适合所有场景<font style="color:rgb(5, 7, 59);">sync.Pool</font> 并不适合所有需要对象池的场景。特别是对于那些需要精确控制对象生命周期的场景,你可能需要实现自定义的对象池。

总的来说,<font style="color:rgb(5, 7, 59);">sync.Pool</font> 是 Go 语言提供的一个非常有用的工具,它可以帮助你减少内存分配和垃圾回收的开销,提高程序的性能。然而,在使用时需要注意其特性和局限,以免发生不可预见的问题。

❤️❤️❤️小郑是普通学生水平,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

http://www.xdnf.cn/news/321463.html

相关文章:

  • 管家婆实用贴-如何在Excel中清除空格
  • Go语言——error、panic
  • 解决0x0000011b共享打印机无法连接!
  • 泛型设计模式实践
  • 初始图形学(7)
  • 2025-05-07-FFmpeg视频裁剪(尺寸调整,画面比例不变)
  • 系统思考:教育焦虑恶性循环分析
  • C语言初阶:数组
  • DeepSeek全域智能革命:从量子纠缠到星际文明的认知跃迁引言:认知边界的坍缩与重构
  • 解决leetcode第3537题填充特殊网格
  • CSS详细学习笔记
  • eclipse常用快捷键
  • Jmeter进行http接口测试
  • 使用VSCode在Windows 11上编译运行项目
  • 005 权限的理解
  • Linux上将conda环境VLLM服务注册为开机自启
  • Java 常用的 ORM框架(对象关系映射)
  • 企业级AI革命!私有化部署开源大模型:数据安全+自主可控,打造专属智能引擎
  • Ubuntu20.04安装使用ROS-PlotJuggler
  • 【MCP】客户端配置(ollama安装、qwen2.5:0.5b模型安装、cherry-studio安装配置)
  • C#与Halcon联合编程
  • 迁移学习:如何加速模型训练和提高性能
  • 锁相环HMC830的调试
  • 缓存替换算法与存储器管理的分页、分段、段页式管理联系
  • http Status 400 - Bbad request 网站网页经常报 HTTP 400 错误,清缓存后就好了的原因
  • 办公学习 效率提升 超级PDF处理软件 转换批量 本地处理
  • android 折叠屏开发适配全解析:多窗口、铰链处理与响应式布局
  • 回溯进阶(一):以全排列问题为例,来展示如何对回溯的纵向和横向进行操作
  • C++ 有哪些标准版本
  • eFish-SBC-RK3576工控板音频接口测试操作指南