MST

星途 面试题库

面试题:Go中defer与并发及异常处理结合考察

在Go语言中,假设有一个并发函数如下: ```go package main import ( "fmt" "time" ) func worker() { defer fmt.Println("worker defer") go func() { defer fmt.Println("nested go func defer") panic("nested panic") }() time.Sleep(2 * time.Second) } ``` 在 `main` 函数中调用 `worker` 函数,程序的输出结果是什么?并详细解释defer在并发和异常处理场景下的执行逻辑。
11.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 程序输出结果
    • 程序首先会输出 worker defer,然后程序会异常退出,不会输出 nested go func defer
  2. defer在并发和异常处理场景下的执行逻辑
    • defer在正常函数中的执行逻辑
      • 在Go语言中,defer 语句会将其后面跟随的函数推迟到包含该 defer 语句的函数即将返回时(包括正常返回和通过 panic 异常返回)执行。在 worker 函数中,defer fmt.Println("worker defer") 会在 worker 函数结束时执行。这里 worker 函数执行到 time.Sleep(2 * time.Second) 后,函数结束,所以会输出 worker defer
    • defer在并发场景下的执行逻辑
      • worker 函数中启动了一个新的 goroutine(go func() {... }())时,这个新的 goroutine 与 worker 函数是并发执行的。新的 goroutine 有自己独立的调用栈,与 worker 函数的调用栈相互独立。
    • defer在异常(panic)处理场景下的执行逻辑
      • 在新的 goroutine 中,当执行到 panic("nested panic") 时,该 goroutine 会发生恐慌(panic)。在这个 goroutine 内部,defer fmt.Println("nested go func defer") 应该在该 goroutine 因为 panic 而结束时执行,但由于这个 goroutine 没有被 recover 捕获,它会导致整个程序异常退出,没有机会执行 nested go func deferdefer 语句。而 worker 函数本身不受这个新 goroutine 内部 panic 的影响,依然按照自己的逻辑执行并输出 worker defer 后结束。如果要执行 nested go func defer,需要在新的 goroutine 内部使用 recover 来捕获 panic。例如:
package main

import (
    "fmt"
    "time"
)

func worker() {
    defer fmt.Println("worker defer")
    go func() {
        defer func() {
            if r := recover(); r!= nil {
                fmt.Println("Recovered from:", r)
                fmt.Println("nested go func defer")
            }
        }()
        panic("nested panic")
    }()
    time.Sleep(2 * time.Second)
}

在上述修改后的代码中,新的 goroutine 内部通过 recover 捕获了 panic,从而可以执行 nested go func defer