基础题
Go 的优势是什么?
- 天然支持并发,通过Goroutine和通道实现的
- 支持静态链接,也就是把依赖也打到可执行文件
- 编译语言,效率更高,相对于php、、python、js
Go 程序中的包是什么?
相当于php中的命名空间 + 类库
make和new有什么区别?
数组和切片的区别是什么?
1、数组长度固定,切片长度不固定
2、**数组是值类型,切片是引用类型。**当切片传递给函数时,即使它是按值传递的,实际还是引用传递
channel有什么作用?
负责协程间通信
什么是 Goroutine?你如何停止它?
协程。使用context包停止
如何在运行时检查变量类型?
反射
defer关键字有什么作用?
提前定义好当前函数返回之前需要执行的代码,比如关闭文件或释放资源等操作
什么是交叉编译?
在一个平台上生成可以在另外一个平台执行的文件。具体命令如下:
bash
# 要去linux下执行
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
# 要去Mac下执行
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
# 要去win下执行
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
进阶题
如何在Go语言中实现错误处理?
通过error 接口,处理非致命性错误,例如打开一个不存在的文件、例如网络请求失败需要重试
通过panic,处理致命错误,需要立即中断,例如数据库挂了
推荐方式:尽量使用error
并发同步是什么?在Go语言中,如何实现并发同步?
多个线程或协程并发执行。golang使用goroutine+channel来实现,需要考虑以下问题:
1、开启协程使用goroutine
2、协程间通信使用channel
3、数据竞争处理使用互斥锁(Mutex)、读写锁(RWMutex)、原子操作(Atomic)
例外:尽量避免使用全局变量
Go语言中的并发安全性是什么?如何确保并发安全性?
数据竞争问题。见上题3
Map是线程安全的吗?
线程不安全, 一个 goroutine 在对 map 进行写的时候,另外的 goroutine 不能进行读和写操作
Go语言的泛型是什么,它们有什么用途?
编写模板适应所有类型,简化代码,否则就需要用接口和类型断言。从1.18版本之后才支持
什么是反射,什么场景使用?
反射是指在程序运行时检查变量和值的类型,并且可以改变它们的值或者调用它们的方法。
使用场景:
1、结构体转json时换key的别名
2、判断变量类型执行不同的方法,如1.18版本之前实现泛型
如何进行垃圾回收的?
三色标记原理、写屏障
GMP调度流程
原子操作和锁的区别
在Go语言中,如何进行网络编程?
使用net包
互斥锁(Mutex)
使用场景:写操作频繁
什么是Mutex互斥锁?它在并发编程中的作用是什么?
Mutex互斥锁是一种并发控制机制,用于保护共享资源的访问,以防止多个goroutine同时对该资源进行修改。它提供了两个基本操作:Lock和Unlock。当一个goroutine获得了Mutex的锁时,其他goroutine将被阻塞,直到该goroutine释放了锁。
读写锁(RWMutex)
使用场景:读操作频频率远高于写操作
有了Mutex为什么还需要RWMutex,解决了什么问题?
虽然Go语言中的Mutex互斥锁可以保证对共享资源的独占访问,但在大量并发读操作和少量并发写操作的场景下,Mutex会造成不必要的锁等待,影响性能。因此,引入了RWMutex读写锁,它在读锁占用的情况下,会阻止写操作,但不阻止读操作;在写锁占用的情况下,会阻止其他goroutine(读和写)进来,整个锁相当于由该goroutine独占。这样可以提高读操作的并发性,从而提高性能。因此,当需要明确区分reader和writer的协程场景,且是大量的并发读、少量的并发写时,可以考虑使用RWMutex替换Mutex
什么是 sync.Once
只执行一次,类似单例模式
sync.Pool 有什么用
需要重复分配、回收内存的地方可以用,如数据库连接池,从而减少并复用内存
有哪些常用的包,分别用来做什么?
WaitGroup:用于等待一组goroutine执行完毕,可以确保主goroutine不会过早退出
Go
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(time.Second)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers finished")
}