Подтвердить что ты не робот

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

Является ли более безопасным или более идиоматичным выдавать несколько операторов defer, зависящих от порядка, или отложить анонимную функцию, которая упаковывает логику?

Примеры:

defer os.Remove(tempFile.Name())
defer tempFile.Close()

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

В приведенном ниже примере есть больше строк, больше "синтаксис", но логика находится в более естественном порядке:

defer func() {
    tempFile.Close()
    os.Remove(tempFile.Name())
}()

Какой из них использовать?

4b9b3361

Ответ 1

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

f, err := ioutil.TempFile("", "prefix")
if err != nil {
  log.Println("creating temp file:", err)
  return
}
defer func() {
  err := f.Close()
  if err != nil {
    log.Println("close:", err)
  }
  err = os.Remove(f.Name())
  if err != nil {
    log.Println("remove:", err)
  }
}()

Если у вас несколько ресурсов, то обычно подходит несколько defer.

Ответ 2

  Если у вас есть несколько ресурсов, то обычно подходит несколько отсрочек.

Апрель 2019 года. Но в этом случае рассмотрим Go 1.13 (четвертый квартал 2019 года), поскольку в нем есть исправление для го выпуска 14939: "runtime: defer is slow" и go выпуска 6980: "cmd/compile: выделить несколько задержек в кадрах стека "

См. Go CL 171758: "cmd/compile, время выполнения: выделение отложенных записей в стеке"

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

Это должно сделать отсрочку (как это часто бывает) быстрее.

Эта оптимизация применяется к 363 из 370 сайтов статической отсрочки в бинарном файле cmd/go.

name     old time/op  new time/op  delta
Defer-4  52.2ns ± 5%  36.2ns ± 3%  -30.70%  (p=0.000 n=10+10)

Октябрь 2019 г. (версия 1.13 выпущена несколько недель назад)

Это подтверждено (Брэд Фицпатрик) with CL 190098:

Стоимость заявления об отсрочке [go test -run NONE -bench BenchmarkDefer$ runtime]

With normal (stack-allocated) defers only:         35.4  ns/op
With open-coded defers:                             5.6  ns/op
Cost of function call alone (remove defer keyword): 4.4  ns/op

Но Дэмиен Гриски добавляет:

Отсрочка становится дешевле, но паника/восстановление дороже.

Cost of defer: 34ns -> 6ns.
Cost of panic/recover: 62ns -> 255ns

Это не плохой компромисс.