ProgrammatieBackend Ontwikkelaar

Hoe werkt het defer-mechanisme in lussen en lambda-functies in Go? Wat kan gevaarlijk zijn aan het gebruik van defer binnen een lus?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

defer stelt de uitvoering van een functie uit tot het verlaten van de omringende functie — zelfs als het verlaten plaatsvindt door paniek of return. Wanneer defer binnen een lus wordt gebruikt, worden alle uitgestelde aanroepen opgestapeld in de defer-aanroepstack en worden ze in omgekeerde volgorde uitgevoerd bij het beëindigen van de omringende functie.

Dit kan leiden tot onverwacht resourceverbruik en vertragingen, aangezien alle uitgestelde functies gelijktijdig worden aangeroepen pas na het verlaten van de functielichaam, en niet na elke iteratie van de lus.

Voorbeeldcode:

func readFiles(files []string) { for _, name := range files { f, _ := os.Open(name) defer f.Close() // bronnen worden pas vrijgegeven na de voltooiing van de gehele functie // verwerking van het bestand ... } }

In dit voorbeeld blijven de bestanden open tot het einde van de functie, wat kan leiden tot een lek van descriptors bij een groot aantal bestanden.

Vraag met een val

Wat gebeurt er als je defer gebruikt om middelen binnen een lus te sluiten? Waarom is dit niet altijd optimaal?

Antwoord: Alle defer-aanroepen worden opgestapeld en worden pas geactiveerd na de voltooiing van de functie, niet na elke iteratie. Dit betekent dat middelen (zoals geopende bestanden) te laat zullen worden vrijgegeven.

Juist:

for _, name := range files { f, _ := os.Open(name) // defer f.Close() // niet doen! // Juist: process(f) f.Close() }

Voorbeelden van echte fouten door onbekendheid met de nuances van het onderwerp


Verhaal

In een logboekbeheerproject deed zich een probleem voor: de dienst stopte plotseling met het openen van nieuwe bestanden, terwijl er maar weinig waren. De reden was defer in de lus. Alle bestanden werden geopend, terwijl hun sluiting tot het einde van de functie werd uitgesteld. Na herschrijven naar een expliciete Close() na verwerking verdween het probleem.


Verhaal

In een dienst die metrics verzamelt voor grote lijsten, werd defer gebruikt voor het resetten van de databaseverbinding binnen de lus van datagegevens. Met het toenemen van het aantal iteraties traden vertragingen op en werd de drempel van geopende verbindingen overschreden, waardoor de dienst begon te falen door fouten "too many open connections".


Verhaal

Een engineer, in de hoop op "elegante" opruiming, paste defer toe in een lus die een groot aantal bestanden leest, wat leidde tot het overschrijden van de limiet voor geopende descriptors op de server in productie en tot een stopzetting van de dienst.