← Назад к вопросам

Что произойдет при панике в горутине?

2.2 Middle🔥 212 комментариев
#Конкурентность и горутины

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Паника в горутине: последствия и обработка

При возникновении паники (panic) в горутине в Go происходит серия событий, которые могут иметь различные последствия в зависимости от архитектуры приложения и наличия обработчиков восстановления.

Немедленные последствия паники

Когда в горутине возникает паника:

  1. Выполнение текущей функции немедленно прекращается
  2. Запускается процесс раскрутки стека (stack unwinding) - Go начинает "подниматься" по стеку вызовов, выполняя отложенные функции (defer)
  3. Если паника не восстанавливается, горутина завершается

Пример возникновения и распространения паники

package main

import "fmt"

func riskyFunction() {
    panic("критическая ошибка!")
}

func main() {
    fmt.Println("Старт программы")
    
    go func() {
        fmt.Println("Горутина запущена")
        riskyFunction()
        fmt.Println("Эта строка никогда не выполнится")
    }()
    
    // Даем время горутине выполниться
    time.Sleep(100 * time.Millisecond)
    fmt.Println("Основная горутина продолжает работу")
}

В этом примере горутина завершится из-за паники, но основная горутина (main) продолжит выполнение, так как паника не распространяется между горутинами.

Ключевой механизм: recover()

Для обработки паник в Go существует функция recover(), которую можно вызвать только внутри отложенной функции (defer):

func safeFunction() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Паника перехвачена: %v\n", r)
            // Здесь можно выполнить очистку ресурсов или логирование
        }
    }()
    
    panic("произошла ошибка")
}

func main() {
    fmt.Println("Начало работы")
    safeFunction()
    fmt.Println("Работа завершена успешно")
}

Важные аспекты поведения паники

  1. Изоляция горутин: Паника в одной горутине не влияет на другие горутины. Каждая горутина имеет собственный стек вызовов и обрабатывает паники независимо.

  2. Работа с отложенными функциями: При раскрутке стека выполняются все отложенные функции текущей горутины:

func exampleWithDefer() {
    defer fmt.Println("Defer 1 выполнен")
    defer fmt.Println("Defer 2 выполнен")
    
    panic("стоп!")
    
    defer fmt.Println("Этот defer никогда не выполнится")
}
  1. Паника в основной горутине: Если паника происходит в основной горутине (main) и не перехватывается, программа завершается с ненулевым кодом возврата:
func main() {
    defer func() {
        fmt.Println("Эта функция выполнится даже при панике")
    }()
    
    panic("фатальная ошибка в main")
    // Программа завершится с кодом 2
}

Рекомендации по обработке паник

  1. Используйте recover() стратегически:

    • В критических участках кода
    • На границах модулей
    • В обработчиках веб-запросов
  2. Логирование и мониторинг:

func handleRequest() {
    defer func() {
        if r := recover(); r != nil {
            log.Printf("Паника в обработчике: %v", r)
            // Отправка метрик, уведомлений и т.д.
        }
    }()
    
    // Код обработки запроса
}
  1. Разделяйте ответственность:
    • Используйте панику только для действительно исключительных ситуаций
    • Для ожидаемых ошибок используйте стандартный механизм возврата ошибок
    • Документируйте функции, которые могут вызывать панику

Типичный сценарий в веб-сервере

func handler(w http.ResponseWriter, r *http.Request) {
    defer func() {
        if rec := recover(); rec != nil {
            http.Error(w, "Внутренняя ошибка сервера", 500)
            log.Printf("Паника в обработчике %s: %v", r.URL.Path, rec)
        }
    }()
    
    // Опасные операции
    processRequest(r)
}

Важно понимать, что паника — это механизм для исключительных ситуаций, а не для обычного управления потоком выполнения. Правильное использование recover() позволяет создавать устойчивые приложения, которые могут продолжить работу даже при возникновении непредвиденных ошибок в отдельных компонентах.