ProgrammierungBackend-Entwickler

Wie funktioniert der defer-Mechanismus in Schleifen und Lambda-Funktionen in Go? Warum kann es gefährlich sein, defer innerhalb einer Schleife zu verwenden?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

defer verschiebt die Ausführung einer Funktion bis zum Verlassen der umgebenden Funktion — selbst wenn der Ausgang aufgrund einer Panik oder eines Returns erfolgt. Wenn defer innerhalb einer Schleife verwendet wird, werden alle aufgeschobenen Aufrufe im Stack der defer-Aufrufe angesammelt und in umgekehrter Reihenfolge ausgeführt, wenn die umgebende Funktion abgeschlossen ist.

Dies kann zu unerwartetem Ressourcenverbrauch und Verzögerungen führen, da alle aufgeschobenen Funktionen erst nach dem Verlassen des Funktionskörpers gleichzeitig aufgerufen werden, und nicht nach jeder Iteration der Schleife.

Beispielcode:

func readFiles(files []string) { for _, name := range files { f, _ := os.Open(name) defer f.Close() // Ressourcen werden erst nach Abschluss der gesamten Funktion freigegeben // Datei verarbeiten ... } }

In diesem Beispiel bleiben die Dateien bis zum Ende der Funktion geöffnet, was zu einem Descriptor-Leck führen kann, wenn viele Dateien geöffnet werden.

Fangfrage

Was passiert, wenn defer zum Schließen von Ressourcen innerhalb einer Schleife verwendet wird? Warum ist das nicht immer optimal?

Antwort: Alle defer-Aufrufe werden angesammelt und wirken erst nach Abschluss der Funktion, nicht nach jeder Iteration. Das bedeutet, dass Ressourcen (z. B. geöffnete Dateien) zu spät freigegeben werden.

Richtig:

for _, name := range files { f, _ := os.Open(name) // defer f.Close() // nicht erlaubt! // Richtig: process(f) f.Close() }

Beispiele für reale Fehler aufgrund fehlenden Wissens über die Feinheiten des Themas


Geschichte

Im Projekt zur Protokollierung trat ein Problem auf: Der Dienst hörte plötzlich auf, neue Dateien zu öffnen, obwohl nur wenige Dateien vorhanden waren. Der Grund war defer in der Schleife. Alle Dateien wurden geöffnet, und ihr Schließen wurde bis zum Ende der Funktion verschoben. Nach der Umstellung auf ein explizites Close() nach der Verarbeitung verschwand das Problem.


Geschichte

In einem Dienst, der Metriken für große Listen sammelte, wurde defer zum Zurücksetzen der Datenbankverbindung innerhalb der Schleife verwendet. Mit steigender Anzahl von Iterationen traten Verzögerungen und das Erreichen des Limits offener Verbindungen auf, der Dienst begann aufgrund von Fehlern "too many open connections" abzustürzen.


Geschichte

Ein Ingenieur verwendete in der Hoffnung auf eine "elegante" Bereinigung defer in einer Schleife zum Lesen einer großen Anzahl von Dateien, was zu einer Überfüllung des Limits offener Deskriptoren auf dem Server in der Produktion und zum Stillstand des Dienstes führte.