面试题答案
一键面试可能遇到的问题
- 竞态条件:多个协程同时对同一文件进行读写操作,可能导致数据不一致。例如,一个协程在读取文件内容时,另一个协程同时进行写入操作,可能会读到不完整或错误的数据。
- 文件描述符耗尽:如果在并发场景中频繁打开文件而没有及时关闭,可能会导致文件描述符耗尽,后续文件操作失败。
避免问题的机制及示例
- 使用互斥锁(sync.Mutex):
package main
import (
"fmt"
"io/ioutil"
"os"
"sync"
)
var mu sync.Mutex
func writeFile(filename string, content []byte) {
mu.Lock()
defer mu.Unlock()
err := ioutil.WriteFile(filename, content, 0644)
if err != nil {
fmt.Println("Write file error:", err)
}
}
func readFile(filename string) {
mu.Lock()
defer mu.Unlock()
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println("Read file error:", err)
return
}
fmt.Println("File content:", string(data))
}
func main() {
var wg sync.WaitGroup
filename := "test.txt"
// 启动写协程
wg.Add(1)
go func() {
defer wg.Done()
writeFile(filename, []byte("Hello, World!"))
}()
// 启动读协程
wg.Add(1)
go func() {
defer wg.Done()
readFile(filename)
}()
wg.Wait()
}
在这个示例中,通过sync.Mutex
确保在同一时间只有一个协程可以进行文件操作,避免竞态条件。
- 使用通道(chan):
package main
import (
"fmt"
"io/ioutil"
"os"
"sync"
)
type FileOp struct {
filename string
content []byte
result chan error
}
func fileOperator(opChan chan FileOp) {
for op := range opChan {
if op.content != nil {
err := ioutil.WriteFile(op.filename, op.content, 0644)
op.result <- err
} else {
data, err := ioutil.ReadFile(op.filename)
if err == nil {
fmt.Println("File content:", string(data))
}
op.result <- err
}
}
}
func main() {
var wg sync.WaitGroup
filename := "test.txt"
opChan := make(chan FileOp)
go fileOperator(opChan)
// 写操作
wg.Add(1)
go func() {
defer wg.Done()
resultChan := make(chan error)
opChan <- FileOp{filename: filename, content: []byte("Hello, again!"), result: resultChan}
err := <-resultChan
if err != nil {
fmt.Println("Write file error:", err)
}
}()
// 读操作
wg.Add(1)
go func() {
defer wg.Done()
resultChan := make(chan error)
opChan <- FileOp{filename: filename, result: resultChan}
err := <-resultChan
if err != nil {
fmt.Println("Read file error:", err)
}
}()
wg.Wait()
close(opChan)
}
通过通道opChan
来顺序处理文件操作,避免多个协程同时操作文件引发的问题。每个操作通过result
通道返回结果,确保操作的完整性和正确性。同时,在主函数结束时关闭opChan
,避免goroutine泄漏。