разница между восстановлением при запуске горутины в новой функции или нет

Речь идет об отсрочке и восстановлении, чтобы поймать ошибку времени выполнения.

версия 1:

func a() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println(r)
        }
    }()
    b()
}

func b() {
    go fmt.Println([]string{}[2])
}

func main() {
    a()
    time.Sleep(1 * time.Second)
    fmt.Println("end")
}

Версия 2 (изменена только функция b()):

func b() {
    go func() {
        fmt.Println([]string{}[2])
    }()
}

разница запуска версии 1:

> go run /tmp/version1.go 
runtime error: index out of range
end

и версия 2:

> go run /tmp/t.go 
panic: runtime error: index out of range

goroutine 5 [running]:
main.b.func1()
    /tmp/t.go:19 +0x109
created by main.b
    /tmp/t.go:20 +0x2b

goroutine 1 [sleep]:
time.Sleep(0x3b9aca00)
    /usr/local/go/src/runtime/time.go:59 +0xf9
main.main()
    /tmp/t.go:25 +0x29
exit status 2

почему он выглядит иначе? спасибо, если кто-то может дать мне подробное сообщение.


person Wu Yunzhou    schedule 17.03.2016    source источник


Ответы (1)


В версии 1 ваша паника возникает в основной горутине, потому что []string{}[2] должен быть разрешен до того, как горутина может быть порождена.

Все аргументы функции должны быть разрешены до того, как она будет отправлена, и горутины ничем не отличаются.

Горутина работает в основном так же, как любой другой вызов функции, за исключением того, что после настройки стека для вызова она выполняется в отдельном контексте (потоке).

во втором примере вы вызываете функцию без аргументов, а затем в этой функции паникуете. Поскольку в горутине нет вызова recovery(), вы видите обработчик паники по умолчанию.

defer/recover() может фиксировать панику только в пределах одной и той же горутины.

Если вы добавите отсрочку/восстановление в начало b, вы сможете захватить его и сделать что угодно (например: распечатать его, как вы сделали в # 1)

person David Budworth    schedule 17.03.2016