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 main import ( "fmt" "io/ioutil" "net/http" "time" "sync" "runtime" ) // 计数器 var counter int = 0 func 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 { break } } end := time.Now() consume := end.Sub(start).Seconds() fmt.Println("程序执行耗时(s):", consume) }
问题
我们可以看到共享内存的方式是可以做到并发,但是我们需要利用共享变量来进行协程的通信,也就需要使用互斥锁来确保数据安全性,导致代码啰嗦,复杂话,不易维护。我们后续使用go的消息传递方式避免这些问题。
消息传递(管道)
//基本的GET请求 package main import ( "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