加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

golang之defer

发布时间:2020-12-16 19:15:40 所属栏目:大数据 来源:网络整理
导读:点击上方 蓝色字体 关注我们 golang 中的延迟调用函数 延迟调用函数 (Deferred Function Calls)的调用方式如下: defer func_name(param-list) 1 执行的时机 func f1() (ret int ) { defer func () ret++ }() return 0 } f2() tmp := 1 = tmp + 10 tmp f3()
                                                                                                     

点击上方蓝色字体关注我们


golang 中的延迟调用函数


延迟调用函数(Deferred Function Calls)的调用方式如下:

defer func_name(param-list)


1 执行的时机


funcf1()(retint){

deferfunc()ret++

}()

return0

}

f2()tmp:=1

=tmp+10

tmp

f3()func(ret retret}(ret)

先不要运行程序,心里记下自己认为分别运行这三个函数的结果,然后我们慢慢分析。



这里先说结论:

网上有篇博文讲的defer的实现方式就是在defer出现的地方插入指令:

CALL runtime.deferproc


然后在函数返回之前的地方插入指令:

CALL runtime.deferreturn

同时由于 return ret这一句并不是原子操作,它是分为两步来执行的:

1)先在栈中写一个值,这个值被当作返回值;

2)然后调用空的return语句。

那么有了defer之后,defer的执行是被插入在return之前赋值指令之后的。

有了这个结论,我们来分析前面的代码的结果:

f1():先给返回的值ret=0赋值,然后执行defer,把ret++,这样最后返回出来的结果就是 1;

f2():return之前 tmp的值是1,执行ret = 1,然后执行defer,把tmp+=10,此时在返回,不影响返回结果,最终结果还是1;

f3():return之前,先执行ret=1的赋值操作,然后,将ret值传递给匿名函数,执行的结果不影响之前的值,所以ret函数最终的返回值是1。

2 执行的顺序


f4()fmt.Println("1-1")

"1-1-1")

"2-2")

"2-2-2")

猜猜看,调用f4之后出现的打印是什么:

结论是


可以看出它是基于先进后出的方式存储defer函数的,也就是逆序执行的

goroutine的控制结构中,有一张表记录defer,调用runtime.deferproc时会将需要defer的表达式写入表中,而在调用runtime.deferreturn的时候,则会依次从defer表中取出并执行。

3 使用defer值得注意的地方

1 经常在加锁的地方紧接着使用 defer 去解锁,这样写是非常方便,不用在加锁之后,每个return的地方都要去解锁,但是别忘了加锁之后要是有阻塞的操作,导致函数一直没有办法返回,那么就出现了问题。

f5()lc.Lock()

lc.Unlock()

for{//长期执行某个操作

if0达到某种条件之后退出

break

return


如上f5(),如果lc这把锁有其他的地方在用,那么就导致了死锁的问题。



扫描二维码关注我们




查看原文:http://www.zoues.com/2016/10/20/golang%e4%b9%8bdefer/

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读