Golang笔记--defer关键字

defer是goland中的一个关键词,用于延迟执行一个函数调用,通常用于在函数返回之前执行一些清理操作,无论函数是否发生错误。当函数中的defer语句被执行时,被延迟的函数调用会被推入一个栈中,然后在函数返回时按照后进先出(LIFO)的顺序执行。defer语句在函数中的位置并不重要,它们会在函数返回之前的任何时候都被执行。如下

package main

import (
	"fmt"
)

func main() {
	defer func() {
		fmt.Println("第一个defer。")
	}()
	defer func() {
		fmt.Println("第二个defer。")
	}()
	defer func() {
		fmt.Println("第三个defer。")
	}()
	fmt.Println("主进程运行结束。")
}

上面案例会输出

主进程运行结束。
第三个defer。
第二个defer。
第一个defer。

defer的机制,在某些资源处理上是很有用的,例如在文件操作中,使用defer关闭文件,无论是否正常读取,都用defer关键字调用关闭操作。

package main

import (
	"fmt"
	"os"
)

func main() {
	_, err := readFile("test.txt")
	if err != nil {
		fmt.Println("读取文件时发生错误:", err)
		return
	}
	fmt.Println("主进程运行结束。")

}

func readFile(filename string) ([]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	// 确保文件在函数返回前被关闭
	defer func() {
		err := file.Close()
		if err != nil {
			fmt.Println("关闭文件时发生错误:", err)
		} else {
			fmt.Println("成功关闭文件:", err)
		}
	}()
	lines := []string{}
	return lines, nil
}
//输出
成功关闭文件: <nil>
主进程运行结束。

当开发中使用defer语句确保在函数返回之前释放锁,避免忘记释放锁导致死锁的情况。

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

func main() {
	var mutex sync.Mutex
	var counter int32
	var wg sync.WaitGroup
	num := 2
	for i := 0; i < num; i++ {
		wg.Add(1)
		go func(id int) {
			fmt.Printf("第 %d 个goroutine尝试进入临界区\n", id)
			mutex.Lock()
			defer func() {
				mutex.Unlock()
				atomic.AddInt32(&counter, 1) // 利用原子操作,增加计数器
				wg.Done()
			}()
			fmt.Printf("第 %d 个goroutine 进入临界区\n", id)
			// 在临界区执行操作,模拟等待时常,例如一些数据库的更新操作
			time.Sleep(time.Second)
			fmt.Printf("第 %d 个goroutine离开临界区\n", id)
		}(i)
	}
	// 等待所有goroutine执行完毕
	wg.Wait()
	// 检查计数器的值,如果所有goroutine都正确释放了锁,计数器应该等于goroutine的数量
	if atomic.LoadInt32(&counter) == int32(num) {
		fmt.Println("所有锁都被正确释放")
	} else {
		fmt.Println("存在锁泄漏")
	}
}

案例输出:

第 1 个goroutine尝试进入临界区
第 1 个goroutine 进入临界区
第 0 个goroutine尝试进入临界区
第 1 个goroutine离开临界区
第 0 个goroutine 进入临界区
第 0 个goroutine离开临界区
所有锁都被正确释放

因此,可以通过defer来确保资源的释放、锁的释放、等其他一些必要的清理操作,尽量避免忘记执行清理操作的风险。

上一篇:记录golang常用库-json处理

下一篇:linux环境PostgreSQL安装

关注公众号

发表评论