面试题答案
一键面试defer关键字的性能影响
- 延迟函数调用开销:每次使用
defer
都会产生一定的函数调用开销,因为需要将延迟函数及其参数压入栈中。当defer
语句执行时,会分配栈空间来存储相关信息,包括函数指针和参数值。例如,在一个循环中多次使用defer
,会不断地进行栈空间的分配和释放,对性能有一定影响。 - 栈空间占用:
defer
函数调用在栈中占用空间,直到其被执行。如果在一个函数中使用大量defer
语句,可能会导致栈空间占用过多,特别是在递归函数中,如果递归深度较深且每次递归都有defer
语句,可能会导致栈溢出。
常见使用场景
- 资源清理:
在上述代码中,package main import ( "fmt" "os" ) func main() { file, err := os.Open("test.txt") if err!= nil { fmt.Println("Error opening file:", err) return } defer file.Close() // 在这里对文件进行读取等操作 // 函数结束时,defer会确保文件被关闭 }
defer file.Close()
确保无论os.Open
之后的代码是否发生错误,文件都会被正确关闭,避免资源泄漏。 - 解锁互斥锁:
这里package main import ( "fmt" "sync" ) var mu sync.Mutex var count int func increment() { mu.Lock() defer mu.Unlock() count++ fmt.Println("Incremented count:", count) }
defer mu.Unlock()
保证了在increment
函数结束时,无论是否发生错误,互斥锁都会被解锁,防止死锁。 - 错误处理和恢复:
在package main import ( "fmt" ) func divide(a, b int) { defer func() { if r := recover(); r!= nil { fmt.Println("Recovered from panic:", r) } }() result := a / b fmt.Println("Result:", result) }
divide
函数中,defer
语句内的匿名函数用于捕获可能发生的panic
,并进行恢复处理,使程序不会因除零等错误而崩溃。