面试题答案
一键面试通过context取消goroutine时确保文件资源正确释放
在Go语言中,可以使用context
包来取消goroutine
,同时使用defer
语句来确保文件资源的正确释放。以下是示例代码:
package main
import (
"context"
"fmt"
"io/ioutil"
"os"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
go func(ctx context.Context) {
file, err := os.Open("test.txt")
if err != nil {
fmt.Println("Failed to open file:", err)
return
}
defer file.Close()
select {
case <-ctx.Done():
fmt.Println("goroutine cancelled, closing file")
default:
data, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println("Failed to read file:", err)
return
}
fmt.Println("File content:", string(data))
}
}(ctx)
time.Sleep(3 * time.Second)
}
在上述代码中:
- 使用
context.WithTimeout
创建一个带有超时的context
,并在主函数结束时调用cancel
函数。 - 在
goroutine
中打开文件后,立即使用defer file.Close()
来确保无论goroutine
如何结束(正常结束或因context
取消而结束),文件都会被关闭。 - 使用
select
语句监听ctx.Done()
通道,当接收到取消信号时,执行相应的清理操作(这里只是打印一条消息)。
复杂场景下处理资源释放以避免内存泄漏
当多个goroutine
之间存在资源依赖时,处理资源释放变得更加复杂。一种常见的方法是使用sync.WaitGroup
来等待所有相关的goroutine
完成,并在主goroutine
中进行统一的资源释放。
以下是一个简单示例,展示两个goroutine
依赖同一个文件资源的情况:
package main
import (
"context"
"fmt"
"io/ioutil"
"os"
"sync"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
var wg sync.WaitGroup
file, err := os.Open("test.txt")
if err != nil {
fmt.Println("Failed to open file:", err)
return
}
defer file.Close()
wg.Add(2)
go func(ctx context.Context, file *os.File) {
defer wg.Done()
select {
case <-ctx.Done():
fmt.Println("goroutine 1 cancelled")
default:
data, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println("Failed to read file in goroutine 1:", err)
return
}
fmt.Println("File content in goroutine 1:", string(data))
}
}(ctx, file)
go func(ctx context.Context, file *os.File) {
defer wg.Done()
select {
case <-ctx.Done():
fmt.Println("goroutine 2 cancelled")
default:
data, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println("Failed to read file in goroutine 2:", err)
return
}
fmt.Println("File content in goroutine 2:", string(data))
}
}(ctx, file)
wg.Wait()
fmt.Println("All goroutines completed, file will be closed automatically by defer")
}
在这个示例中:
- 使用
sync.WaitGroup
来等待两个goroutine
完成。 - 主
goroutine
打开文件,并在函数结束时通过defer
关闭文件。 - 每个
goroutine
在结束时调用wg.Done()
来通知主goroutine
自己已完成。 - 使用
context
来取消goroutine
,并在goroutine
中通过select
监听ctx.Done()
通道,以便在取消时进行相应的清理操作。
通过这种方式,可以有效地避免内存泄漏,并确保资源在所有相关goroutine
结束后正确释放。