web-dev-qa-db-fra.com

Plusieurs fonctions différées vs fonction anonyme différée

Est-il plus sûr ou plus idiomatique d'émettre plusieurs instructions defer qui dépendent de l'ordre, ou de différer une fonction anonyme qui conditionne la logique?

Exemples:

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

Dans le cas ci-dessus, la syntaxe est minimale, mais l'ordre des différés est inversé dans la logique à exécuter.

Dans le cas ci-dessous, il y a plus de lignes, plus de "syntaxe", mais la logique est dans un ordre plus naturel:

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

Lequel utiliser?

25
Vlad Didenko

Dans cet exemple, la fonction anonyme est plus facile à lire, en particulier une fois que vous avez ajouté la gestion des erreurs.

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)
  }
}()

Si vous avez plusieurs ressources, plusieurs defers sont généralement appropriés.

26
Ross Light

Si vous avez plusieurs ressources, plusieurs reports sont généralement appropriés.

Avril 2019: Mais dans ce cas, considérez Go 1.13 (Q4 2019), car il intègre un correctif pour passez au problème 14939: "runtime: le délai est lent" et passez au problème 6980: "cmd/compile: allouer quelques defers dans les frames de pile"

Voir Go CL 171758: "cmd/compile, runtime: allocate defer records on the stack"

Lorsqu'un report est exécuté au plus une fois dans un corps de fonction, nous pouvons lui allouer l'enregistrement de report sur la pile plutôt que sur le tas.

Cela devrait accélérer les différés comme celui-ci (qui sont très courants).

Cette optimisation s'applique à 363 des 370 sites de report statique dans le binaire 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)

Oct.2019 (Go 1.13 est sorti il ​​y a quelques semaines)

Ceci est confirmé (Brad Fitzpatrick) avec CL 190098 :

Déclaration du coût du report [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

Mais Damien Grisky ajoute :

Le report coûte moins cher, mais la panique/récupération coûte plus cher.

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

Ce n'est pas un mauvais compromis.

2
VonC