面试题答案
一键面试实现方案
- 文件描述符关闭:使用
defer
关键字来确保在Goroutine结束时关闭所有打开的文件描述符。defer
语句会在函数返回时按照后进先出(LIFO)的顺序执行,这样可以保证文件描述符在函数结束时被正确关闭。 - 共享数据并发安全:使用
sync.Mutex
来保护共享数据。在访问共享数据之前,先获取锁,访问结束后释放锁,从而避免竞态条件。
代码示例
package main
import (
"fmt"
"io/ioutil"
"sync"
)
// 定义共享数据结构
type SharedData struct {
data int
mu sync.Mutex
}
// Goroutine函数
func worker(shared *SharedData, filePaths []string, wg *sync.WaitGroup) {
defer wg.Done()
// 打开文件描述符
var files []*ioutil.File
for _, filePath := range filePaths {
file, err := ioutil.TempFile("", filePath)
if err != nil {
fmt.Printf("Failed to open file %s: %v\n", filePath, err)
return
}
files = append(files, file)
}
defer func() {
for _, file := range files {
file.Close()
}
}()
// 操作共享数据
shared.mu.Lock()
shared.data++
shared.mu.Unlock()
// 模拟一些工作
fmt.Println("Worker is doing some work...")
}
func main() {
shared := &SharedData{}
filePaths := []string{"file1.txt", "file2.txt"}
var wg sync.WaitGroup
wg.Add(1)
go worker(shared, filePaths, &wg)
wg.Wait()
fmt.Printf("Final shared data: %d\n", shared.data)
}
在上述代码中:
SharedData
结构体包含一个整数类型的数据data
和一个sync.Mutex
类型的锁mu
,用于保护data
的并发访问。worker
函数接收共享数据指针、文件路径切片和sync.WaitGroup
指针。在函数内部,使用defer
来关闭打开的文件描述符,并通过锁来确保共享数据的并发安全。main
函数启动一个Goroutine并等待它完成,最后打印共享数据的最终值。