go WaitGroup与defer

WaitGroup与defer

WaitGroup

WaitGroup 是一个结构体类型,用于等待一批Go协程执行结束。程序会一直阻塞,直到这些协程全部执行完毕。主线程(goroutine)才会执行

WaitGroup 的使用

通过前面信道一文,我们可以利用信道实现和waitgroup一样的效果。代码如下:

func main() {
	fmt.Println("程序开始")
	c := make(chan int, 5)
	for i := 0; i < 5; i++ {
		go Test(i, c)
	}

	for i:=0; i<cap(c);i++{  // 这里不能用len,原因在于,主goroutine执行到这一步时,其他的goroutine未必执行完了,因此 信道 c 中的长度不等于5.会报deadlock错误
		<- c
	}
	fmt.Println("程序结束")

}

func Test(s int, c chan int) {
	fmt.Println(s)
	c <- s
}

`
程序开始
4
0
1
2
3
程序结束
`

可以看出,等待5个子goroutine执行,代码就有一丢丢复杂了,如果要等待更多,代码量虽然不会增加,但是 信道的容量确需要 变化。接下来我们看看使用 waitgroup实现的代码。

func main() {
	fmt.Println("程序开始")
    // WaitGroup 是 结构体, 值类型,不用初始化就有默认零值;当参数传递,如果改原来的,需要取地址
	var wg = sync.WaitGroup{}   
	for i := 0; i < 5; i++ {
		go Test2(i, &wg)   
		wg.Add(1)   // 每循环一次就启动一个任务
	}
	//wg.Add(5)   // 也可以一次性启动5个
	wg.Wait()  // 等待所有任务完成
	fmt.Println("程序结束")
}

func Test2(s int, wg *sync.WaitGroup) {
	fmt.Println(s)
	wg.Done()  // 结束一个任务
}

可以看出,使用waitgroup,代码就简单很多了,多一个子goroutine,只需要多启动一个任务即可。

defer

defer 语句的用途是:含有 defer 语句的函数,会在该函数将要返回之前,调用另一个函数。这个定义可能看起来很复杂,我们通过一个示例就很容易明白了。

func main() {
	Test3()
}

func Test3()  {
	defer finally()   // 先注册,后执行  哪怕下方代码出错也会执行
    // finally()
	fmt.Println("Test3: 我开始执行了")
	fmt.Println("Test3: 我执行结束了")
}

func finally()  {
	fmt.Println("到我执行了")
}

`
使用defer打印结果:
    Test3: 我开始执行了
    Test3: 我执行结束了
    到我执行了
`
`
不使用defer打印结果:
    到我执行了
    Test3: 我开始执行了
    Test3: 我执行结束了
`

简单点说就是: 注册代码,延迟调用,等函数执行完后,按注册顺序倒序执行defer,先注册的,最后执行。

并且defer,不仅可以用于函数,也可以用于方法的调用。感兴趣的小伙伴可以自己试试。

实参取值

在 Go 语言中,并非在调用延迟函数的时候才确定实参,而是当执行 defer 语句的时候,就会对延迟函数的实参进行求值。

通过一段例子,就能很好理解了

func main() {
    i := 4
    defer finally(i)  // 定义的时候就已经把参数传入了,只是还没有执行
    defer finally(&i)
    i++
}

func finally(i int)  {
	fmt.Println(i)   // 4
}
func finally2(i *int)  {
	fmt.Println(*i)   // 5
}

`
5
4
`

因此,值类型数据使用 defer 函数传参后,值改变不影响 defer后函数的参数。但是引用类型会影响。

defer 栈

当一个函数内多次调用 defer 时,Go 会把 defer 调用放入到一个栈中,随后按照后进先出(Last In First Out, LIFO)的顺序执行。代码示例可以看看上方。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go&Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值