Горутины: отложенные вызовы функций
Отложенный вызов функции — это вызов функции, который следует за defer ключевым словом. Ключевое defer слово и вызов отложенной функции вместе образуют оператор отсрочки. Как и вызовы функций горутины, все результаты вызова функции, если вызываемая функция имеет возвращаемые результаты, должны быть отброшены в операторе вызова функции.
При выполнении инструкции отсрочки отложенный вызов функции не выполняется немедленно. Вместо этого он помещается в очередь отложенных вызовов, поддерживаемую вызывающей горутиной. После того, как вызов функции fc(...) возвращается, но еще не полностью существует, и переходит в фазу выхода, все отложенные вызовы функций, помещенные в очередь отложенных вызовов во время выполнения вызова функции, будут удалены из очереди отложенных вызовов и выполнены в порядке очереди, обратном порядку, в котором они были помещены в очередь отложенных вызовов. Как только все эти отложенные вызовы выполнены, вызов функции fc(...) полностью завершается.
Вот простой пример, показывающий, как использовать отложенные вызовы функций.
Пришло время поработать с кодом!
Результат.
Вот еще один пример, немного более сложный. Пример будет печатать 0 до 9, каждый в строке в их естественном порядке.
Пришло время поработать с кодом!
Отложенные вызовы функций могут изменить именованные результаты возврата вложенных функций.
Пример.
Пришло время поработать с кодом!
Момент оценки аргументов отложенных вызовов функций
Все аргументы отложенного вызова функции оцениваются в момент выполнения соответствующего оператора отложенного вызова, то есть когда отложенный вызов помещается в очередь отложенных вызовов. Результаты оценки используются, когда отложенный вызов выполняется позже во время существующей фазы окружающего вызова (вызывающий отложенный вызов).
Выражения в теле вызова анонимной функции, независимо от того, является ли вызов общим или отложенным/вызовом подпрограммы, оцениваются во время выполнения вызова анонимной функции.
Пример.
Пришло время поработать с кодом!
Результат.
Первый цикл печатается i как 2 и 1 как 0 последовательность. Второй цикл всегда печатается i как 3, поскольку при вызове трех fmt.Println вызовов анонимной функции значение переменной цикла i изменилось на 3.
Чтобы второй цикл печатал тот же результат, что и первый, мы можем изменить второй цикл следующим образом.
Пришло время поработать с кодом!
Или же так.
Пришло время поработать с кодом!
Те же самые правила оценки момента аргумента также применяются к вызовам функций горутины. Следующая программа выведет 123 789.
Пришло время поработать с кодом!
Кстати, Time.Sleep синхронизацию с помощью вызовов в настоящих проектах использовать не стоит. Если программа запускается на компьютере, центральные процессоры которого заняты множеством других программ, работающих на этом компьютере, вновь созданная горутина может никогда не получить возможности выполниться до выхода программы. Мы должны использовать методы синхронизации в конкурентной модели пакета sync, чтобы выполнять синхронизацию в продакшн проектах.
Необходимость отложенной функции
В приведенных выше примерах отложенные вызовы функций не являются абсолютно необходимыми. Однако функция отложенного вызова функции является необходимой функцией для механизма паники и восстановления, который будет представлен ниже.
Отложенные вызовы функций также могут помочь нам написать более чистый и надежный код.