Паника, как суслик

Ошибки при выполнении программы на Go (после успешной компиляции и при запуске процесса ОС) принимают форму паники. Их можно запустить двумя способами:

  1. сознательно используя встроенную функцию panic:

panic принимает в качестве аргумента любое значение типа, реализующего пустой интерфейс (interface {}), который удовлетворяет все типы.

2. вызвано ошибкой программирования, вызывающей панику во время выполнения:

Запуск паники во время выполнения семантически аналогичен вызову panic функции со значениями типа интерфейса runtime.Error.

2-й выход содержит дополнительную информацию о сигнале. 0x8 (SIGFPE) сообщает о фатальной арифметической ошибке.

Чтобы полностью понять механику паники, давайте сначала углубимся в структуру запущенной программы Go.

Горутины

Программа, реализованная в Go во время выполнения, состоит из одной или нескольких горутин. S pecification определяет goroutine в разделе, посвященном инструкции go:

Оператор go запускает выполнение вызова функции как независимый параллельный поток управления, или goroutine, в том же адресном пространстве.

Go - это параллельный язык. Это связано с тем, что он поставляется с функциями, поддерживающими параллельное программирование, такими как оператор для одновременного запуска вещей (оператор go) или механизм для простого взаимодействия между такими параллельными вещами (каналы). Но что значит быть параллельным? Как это связано с вездесущим параллелизмом?

Состав

Параллелизм - это способ построения вещей как набора независимых задач. Речь идет о структуре (дизайне). Параллельная программа обрабатывает отдельные задачи, например, неважно. каков порядок их исполнения. Параллелизм - это одновременное выполнение двух или более задач. Буквально одновременно многие потоки выполнения продвигаются вперед. Это нужно делать на многоядерной машине - «имитировать» это невозможно.

Параллелизм - это более общий термин, чем параллелизм. Среда выполнения параллельной программы может (но не обязательно) использовать преимущества нескольких ядер и выполнять множество вычислений одновременно. Если доступно только одно ядро, используйте f.ex. временные интервалы (разделить время на дискретные интервалы и назначить их разным задачам) по-прежнему параллельны, но параллелизм технически невозможен.

Параллелизм - это одновременное решение множества задач. Параллелизм - это одновременное выполнение множества задач.

Роб Пайк

Основная горутина

Он запускает функцию main из пакета main (точка входа для каждой программы, написанной на Go). Если эта горутина завершает выполнение, вся программа завершается. Среда выполнения не ждет, пока завершатся другие горутины.

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

Горутины живут в одном адресном пространстве

Заявление об отсрочке

Это позволяет выполнять функцию (-ы) после завершения охватывающей функции (той, где используется defer), что происходит:

  1. в операторе возврата:

2. при достижении конца тела функции:

3. во время паники:

Значение функции и переданные аргументы оцениваются в точке инструкции defer, а не во время фактического вызова:

Каждая функция может иметь внутри множество операторов defer. Порядок вызовов - последний пришел - первый вышел (например, отложенные вызовы будут помещены в стек):

Также допустимы вызовы методов:

и он выводит «Внутренний метод», как и следовало ожидать.

Когда значение функции равно нулю, программа запаникует. Однако этого не произойдет в момент, когда выполняется оператор defer, а когда срабатывает фактический вызов отложенных функций:

Внутри отложенной функции возможно вмешательство в именованный возвращаемый параметр. Если имя не указано, то изменение значения возвращаемой переменной через закрытие не повлияет:

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

Паника

Когда произвольная функция f паникует, из приведенных выше примеров мы видели, что вызовы функций, отложенные в f, будут вызываться в порядке последнего поступления. Что тогда происходит? После этого для вызывающей стороны f такой процесс будет повторяться - сработают его отложенные функции. И так до функции верхнего уровня в горутине f. Наконец, вызываются отложенные функции для функции верхнего уровня, и программа завершается. Это похоже на всплытие на вершину цепочки вызовов:

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

Паниковать еще больше

Что произойдет после запуска новой паники внутри отложенной функции?

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

Восстанавливаться

Встроенная функция recovery позволяет увидеть, была ли вызвана паника, и останавливает ее распространение. Возвращаемое значение - это либо параметр, переданный в panic (если паника происходит), либо ноль. После вызова текущая последовательность действий при панике останавливается, и программа ведет себя так, как если бы паника никогда не происходила с точки вызова функции, внутри которой вызывается отложенная функция recovery:

Разрешено вызывать recovery вне отложенной функции, но nil всегда будет возвращаться.

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

Если вам понравился пост и вы хотите получать новости о новых, пожалуйста, подпишитесь на меня. Помогите другим узнать об этой истории, нажав ❤ ниже.

Ресурсы