面试题答案
一键面试- 使用
sync.Mutex
保护共享资源:- 对于共享内存,使用
sync.Mutex
来防止多个goroutine同时访问和修改。 - 示例代码如下:
- 对于共享内存,使用
package main
import (
"fmt"
"sync"
)
var (
sharedData int
mu sync.Mutex
)
func worker(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
defer mu.Unlock()
// 操作共享资源
sharedData++
fmt.Printf("goroutine modified sharedData to %d\n", sharedData)
}
- 在上述代码中,
worker
函数在操作共享资源sharedData
前获取mu
互斥锁,操作完成后通过defer mu.Unlock()
释放锁,确保在任何时刻只有一个goroutine能操作sharedData
,避免数据竞争。
- 文件操作的资源释放:
- 当操作文件这类共享资源时,使用
defer
来关闭文件句柄。 - 示例代码如下:
- 当操作文件这类共享资源时,使用
package main
import (
"fmt"
"io/ioutil"
"sync"
)
func readFile(wg *sync.WaitGroup) {
defer wg.Done()
file, err := ioutil.ReadFile("test.txt")
if err != nil {
fmt.Printf("Error reading file: %v\n", err)
return
}
defer func() {
// 这里可以对文件关闭进行错误处理,例如在更复杂场景下记录日志等
_ = file.Close()
}()
// 处理文件内容
fmt.Printf("File content: %s\n", file)
}
- 在
readFile
函数中,defer
确保在函数结束时文件句柄会被关闭,防止资源泄漏。
- 使用
sync.WaitGroup
等待所有goroutine完成:- 为了确保所有goroutine都完成操作并释放资源后程序才退出,使用
sync.WaitGroup
。 - 示例代码结合前面两个示例:
- 为了确保所有goroutine都完成操作并释放资源后程序才退出,使用
package main
import (
"fmt"
"io/ioutil"
"sync"
)
var (
sharedData int
mu sync.Mutex
)
func worker(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
defer mu.Unlock()
// 操作共享资源
sharedData++
fmt.Printf("goroutine modified sharedData to %d\n", sharedData)
}
func readFile(wg *sync.WaitGroup) {
defer wg.Done()
file, err := ioutil.ReadFile("test.txt")
if err != nil {
fmt.Printf("Error reading file: %v\n", err)
return
}
defer func() {
// 这里可以对文件关闭进行错误处理,例如在更复杂场景下记录日志等
_ = file.Close()
}()
// 处理文件内容
fmt.Printf("File content: %s\n", file)
}
func main() {
var wg sync.WaitGroup
numWorkers := 3
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go worker(&wg)
}
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go readFile(&wg)
}
wg.Wait()
fmt.Println("All goroutines completed.")
}
- 在
main
函数中,通过wg.Add(1)
为每个goroutine增加计数,wg.Done()
在每个goroutine结束时减少计数,wg.Wait()
等待所有goroutine完成,保证所有资源都能正确释放。
通过上述sync.Mutex
、sync.WaitGroup
等同步机制与defer
语句配合,能够有效避免资源泄漏和数据竞争问题,实现对共享资源在并发环境下的安全操作。