Heim  >  Artikel  >  Backend-Entwicklung  >  Was ist die Anweisung zur verzögerten Ausführung in der Go-Sprache?

Was ist die Anweisung zur verzögerten Ausführung in der Go-Sprache?

青灯夜游
青灯夜游Original
2023-01-11 18:28:571357Durchsuche

In der Go-Sprache ist die Anweisung zur verzögerten Ausführung die Defer-Anweisung und die Syntax lautet „jede Anweisung verzögern“. Die Defer-Anweisung verzögert die Verarbeitung der darauf folgenden Anweisungen. Wenn die Funktion, zu der die Defer-Anweisung gehört, zurückkehrt, werden die verzögerten Anweisungen in der umgekehrten Reihenfolge der Defer-Anweisung ausgeführt wird zuletzt ausgeführt, und die zuletzt aufgeschobene Anweisung wird zuerst ausgeführt.

Was ist die Anweisung zur verzögerten Ausführung in der Go-Sprache?

Die Betriebsumgebung dieses Tutorials: Windows 7-System, GO Version 1.18, Dell G3-Computer.

Anweisung zur verzögerten Ausführung (Defer-Anweisung) in der Go-Sprache

Es gibt eine Anweisung zur verzögerten Ausführung in der Go-Sprache, die durch das Schlüsselwort defer identifiziert wird.

Das Schlüsselwort defer verzögert die Verarbeitung der darauf folgenden Anweisungen. Wenn die Funktion, zu der defer gehört, zurückkehrt, werden die verzögerten Verarbeitungsanweisungen in der umgekehrten Reihenfolge von defer ausgeführt wird zuletzt ausgeführt. Die zuletzt zurückgestellte Anweisung wird zuerst ausgeführt.

Das Format ist wie folgt:

defer 任意语句

Die Anweisungen nach defer werden nicht sofort ausgeführt. Wenn die Funktion, zu der defer gehört, zurückkehrt, werden alle defer-Anweisungen im Funktionskörper in umgekehrter Reihenfolge ausgeführt Aussehen, das heißt, die letzte Anweisung im Funktionskörper Eine Defer-Anweisung wird zuerst ausgeführt.

package main

import "fmt"

func main(){
	fmt.Println("start now")
	defer fmt.Println("这是第一句defer语句")
	defer fmt.Println("这是第二句defer语句")
	defer fmt.Println("这是第三句defer语句")
	fmt.Println("end")
}

Das Ausführungsergebnis lautet wie folgt:

start now
end
这是第三句defer语句
这是第二句defer语句
这是第一句defer语句

Da die Defer-Anweisung aufgerufen wird, wenn die aktuelle Funktion kurz vor der Rückkehr steht, wird Defer häufig zum Freigeben von Ressourcen verwendet.

Die Verarbeitungsreihenfolge mehrerer verzögerter Ausführungsanweisungen

Wenn mehrere Verzögerungsverhalten registriert werden, werden sie in umgekehrter Reihenfolge ausgeführt (ähnlich einem Stapel, d. h. der letzte Eingang, der erste Ausgang). Der folgende Code druckt eine Reihe numerischer Anweisungen verzögern die Verarbeitung in der Reihenfolge wie folgt:

package main
import (
    "fmt"
)
func main() {
    fmt.Println("defer begin")
    // 将defer放入延迟调用栈
    defer fmt.Println(1)
    defer fmt.Println(2)
    // 最后一个放入, 位于栈顶, 最先调用
    defer fmt.Println(3)
    fmt.Println("defer end")
}

Die Codeausgabe lautet wie folgt:

defer begin
defer end
3
2
1

Die Ergebnisanalyse lautet wie folgt:

  • Die Verzögerungsreihenfolge des Codes ist gegenüber der endgültigen Ausführungsreihenfolge umgekehrt.

  • Der verzögerte Aufruf erfolgt, wenn die Funktion endet, in der sich defer befindet. Das Ende der Funktion kann sein, wenn sie normal zurückkehrt oder wenn eine Ausfallzeit auftritt.

Verwenden Sie verzögerte Ausführungsanweisungen, um Ressourcen freizugeben, wenn die Funktion beendet wird.

Die Verarbeitung gepaarter Vorgänge im Geschäfts- oder Logikbereich ist relativ umständlich, z. B. das Öffnen und Schließen von Dateien, das Empfangen und Beantworten von Anfragen sowie das Sperren und Entsperren usw. Unter diesen Vorgängen wird am häufigsten das korrekte Freigeben und Schließen von Ressourcen bei jedem Funktionsausgang übersehen.

Die Defer-Anweisung ist genau die Anweisung, die ausgeführt wird, wenn die Funktion beendet wird. Daher kann die Verwendung von Defer Probleme mit der Ressourcenfreigabe sehr bequem lösen.

1) Verzögertes gleichzeitiges Entsperren verwenden

Im folgenden Beispiel wird die Karte gleichzeitig in der Funktion verwendet. Zur Vermeidung von Race Conditions wird sync.Mutex zum Sperren verwendet:

var (
    // 一个演示用的映射
    valueByKey      = make(map[string]int)
    // 保证使用映射时的并发安全的互斥锁
    valueByKeyGuard sync.Mutex
)
// 根据键读取值
func readValue(key string) int {
    // 对共享资源加锁
    valueByKeyGuard.Lock()
    // 取值
    v := valueByKey[key]
    // 对共享资源解锁
    valueByKeyGuard.Unlock()
    // 返回值
    return v
}

Die Codebeschreibung lautet folgt:

  • Zeile 3, Instanziieren einer Karte, der Schlüssel ist vom Typ String und der Wert ist int.

  • Zeile 5: Die Karte ist standardmäßig nicht parallelitätssicher. Bereiten Sie einen sync.Mutex-Mutex vor, um den Kartenzugriff zu schützen.

  • Zeile 9: Die Funktion readValue() gibt einen Schlüssel aus und gibt den Wert zurück, nachdem sie den Wert aus der Karte abgerufen hat. Diese Funktion wird in einer gleichzeitigen Umgebung verwendet und muss die Sicherheit der Parallelität gewährleisten.

  • Zeile 11, Mutex zum Sperren verwenden.

  • Zeile 13, holen Sie sich den Wert aus der Karte.

  • Zeile 15, Entsperren mit Mutex.

  • Zeile 17 gibt den erhaltenen Kartenwert zurück.

Verwenden Sie die Defer-Anweisung, um die obige Anweisung zu vereinfachen. Weitere Informationen finden Sie im folgenden Code.

func readValue(key string) int {
    valueByKeyGuard.Lock()
   
    // defer后面的语句不会马上调用, 而是延迟到函数结束时调用
    defer valueByKeyGuard.Unlock()
    return valueByKey[key]
}

Die Zeilen 6 bis 8 des obigen Codes sind Modifikationen und Ergänzungen zum vorherigen Code. Die Codebeschreibung lautet wie folgt:

  • Zeile 6 verwendet die Defer-Anweisung, um das Entsperren nach dem Sperren des Mutex hinzuzufügen wird nicht sofort ausgeführt, sondern wird ausgeführt, wenn die Funktion readValue() zurückkehrt.

  • Zeile 8: Der Vorgang zum Abfragen und Zurückgeben des Werts aus der Karte ist derselbe wie beim Schreiben ohne Verwendung eines Mutex. Im Vergleich zum obigen Code ist dieser Schreibvorgang einfacher.

2) Die Verwendung des Dateihandles mit verzögerter Freigabe

Dateivorgänge erfordern mehrere Prozesse: Öffnen der Datei, Abrufen und Betreiben von Dateiressourcen und Schließen der Ressourcen. Wenn die Dateiressourcen nach Abschluss des Vorgangs nicht geschlossen werden, wird der Vorgang ausgeführt Da die Dateiressourcen niemals freigegeben werden können, wird im folgenden Beispiel eine Funktion zum Abrufen der Dateigröße basierend auf dem Dateinamen implementiert. Die Funktion erfordert Vorgänge wie das Öffnen der Datei, das Abrufen der Dateigröße und das Schließen der Datei . Da jede Systemoperation eine Fehlerbehandlung erfordert, führt jeder Verarbeitungsschritt zu einem Fehler. Beim Beenden müssen daher Ressourcen freigegeben werden, und wir müssen beim Beenden der Funktion genau darauf achten, dass die Dateiressourcen korrekt freigegeben werden folgender Code:

// 根据文件名查询其大小
func fileSize(filename string) int64 {
    // 根据文件名打开文件, 返回文件句柄和错误
    f, err := os.Open(filename)
    // 如果打开时发生错误, 返回文件大小为0
    if err != nil {
        return 0
    }
    // 取文件状态信息
    info, err := f.Stat()
   
    // 如果获取信息时发生错误, 关闭文件并返回文件大小为0
    if err != nil {
        f.Close()
        return 0
    }
    // 取文件大小
    size := info.Size()
    // 关闭文件
    f.Close()
   
    // 返回文件大小
    return size
}

Die Codebeschreibung lautet wie folgt:

  • Zeile 2, Funktion zur Erfassung der Dateigröße definieren, der Rückgabewert ist der 64-Bit-Dateigrößenwert.

  • Zeile 5: Verwenden Sie die vom Betriebssystempaket bereitgestellte Funktion Open (), um eine Datei basierend auf dem angegebenen Dateinamen zu öffnen, und geben Sie das zum Ausführen der Datei verwendete Handle und den Betriebsfehler zurück.

  • Zeile 8: Wenn während des Öffnungsvorgangs ein Fehler auftritt, z. B. wenn die Datei nicht gefunden wird, die Datei belegt ist usw., wird die Dateigröße als 0 zurückgegeben.

  • 第 13 行,此时文件句柄 f 可以正常使用,使用 f 的方法 Stat() 来获取文件的信息,获取信息时,可能也会发生错误。

  • 第 16~19 行对错误进行处理,此时文件是正常打开的,为了释放资源,必须要调用 f 的 Close() 方法来关闭文件,否则会发生资源泄露。

  • 第 22 行,获取文件大小。

  • 第 25 行,关闭文件、释放资源。

  • 第 28 行,返回获取到的文件大小。

在上面的例子中,第 25 行是对文件的关闭操作,下面使用 defer 对代码进行简化,代码如下:

func fileSize(filename string) int64 {
    f, err := os.Open(filename)
    if err != nil {
        return 0
    }
    // 延迟调用Close, 此时Close不会被调用
    defer f.Close()
    info, err := f.Stat()
    if err != nil {
        // defer机制触发, 调用Close关闭文件
        return 0
    }
    size := info.Size()
    // defer机制触发, 调用Close关闭文件
    return size
}

代码中加粗部分为对比前面代码而修改的部分,代码说明如下:

  • 第 10 行,在文件正常打开后,使用 defer,将 f.Close() 延迟调用,注意,不能将这一句代码放在第 4 行空行处,一旦文件打开错误,f 将为空,在延迟语句触发时,将触发宕机错误。

  • 第 16 行和第 22 行,defer 后的语句(f.Close())将会在函数返回前被调用,自动释放资源。

【相关推荐:Go视频教程编程教学

Das obige ist der detaillierte Inhalt vonWas ist die Anweisung zur verzögerten Ausführung in der Go-Sprache?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn