面试题答案
一键面试资源管理策略
- 及时关闭资源:在使用完文件、网络连接等资源后,应及时关闭。例如使用
os.File
时,在函数结束时调用file.Close()
。
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("test.txt")
if err != nil {
fmt.Println("Open file error:", err)
return
}
defer file.Close()
// 对文件进行操作
}
- 控制Goroutine数量:使用
sync.WaitGroup
和限制通道(buffered channel)来控制Goroutine的并发数量。
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup, sem chan struct{}) {
defer wg.Done()
sem <- struct{}{}
fmt.Printf("Worker %d started\n", id)
// 模拟工作
// 工作完成
<-sem
fmt.Printf("Worker %d finished\n", id)
}
func main() {
var wg sync.WaitGroup
numWorkers := 5
sem := make(chan struct{}, 3)
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go worker(i, &wg, sem)
}
wg.Wait()
}
数据结构设计策略
- 避免循环引用:确保数据结构之间不存在循环引用,否则垃圾回收器(GC)无法回收相关内存。例如在设计链表时,双向链表要注意避免循环引用。
package main
import "fmt"
// 单向链表节点
type Node struct {
value int
next *Node
}
func main() {
head := &Node{value: 1}
node2 := &Node{value: 2}
node3 := &Node{value: 3}
head.next = node2
node2.next = node3
// 这里没有循环引用问题
}
- 合理选择数据结构:根据实际需求选择合适的数据结构,如使用
map
时,及时删除不再使用的键值对。
package main
import (
"fmt"
)
func main() {
m := make(map[string]int)
m["key1"] = 1
m["key2"] = 2
// 删除不再使用的键值对
delete(m, "key1")
fmt.Println(m)
}
通信机制策略
- 确保通道关闭:在使用通道进行通信时,要确保发送方适时关闭通道,避免接收方一直阻塞。
package main
import (
"fmt"
)
func producer(ch chan int) {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}
func consumer(ch chan int) {
for num := range ch {
fmt.Println("Received:", num)
}
}
func main() {
ch := make(chan int)
go producer(ch)
consumer(ch)
}
- 避免死锁:在使用多个通道和Goroutine进行复杂通信时,要仔细设计逻辑,避免死锁。例如合理安排
select
语句。
package main
import (
"fmt"
)
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
ch1 <- 1
num := <-ch2
fmt.Println("Received from ch2:", num)
}()
go func() {
ch2 <- 2
num := <-ch1
fmt.Println("Received from ch1:", num)
}()
select {}
}
这里 select {}
只是为了防止主函数退出,实际应用中可根据需求替换。