1 package once
2 import "sync"
3 import "sync/atomic"
4
5 type Once struct {
6 m sync.Mutex
7 done uint32
8 }
9
10 func (o *Once) Do(f func()) {
11 if atomic.LoadUint32(&o.done) == 1 {
12 return
13 }
14 o.m.Lock()
15 defer o.m.Unlock()
16 if o.done == 0 {
17 defer atomic.StoreUint32(&o.done, 1)
18 f()
19 }
20 }
上面代码的汇编代码如下
➜ gopath /usr/local/go/bin/go tool compile -N -l -S once.go "".(*Once).Do STEXT size=400 args=0x10 locals=0xb0 0x0000 00000 (once.go:10) TEXT "".(*Once).Do(SB), ABIInternal, $176-16 0x0000 00000 (once.go:10) MOVQ (TLS), CX 0x0009 00009 (once.go:10) LEAQ -48(SP), AX 0x000e 00014 (once.go:10) CMPQ AX, 16(CX) 0x0012 00018 (once.go:10) JLS 390 0x0018 00024 (once.go:10) SUBQ $176, SP 0x001f 00031 (once.go:10) MOVQ BP, 168(SP) 0x0027 00039 (once.go:10) LEAQ 168(SP), BP 0x002f 00047 (once.go:10) FUNCDATA $0, gclocals·8f42dbe77bd9af60c6ae2756bb267b26(SB) 0x002f 00047 (once.go:10) FUNCDATA $1, gclocals·b734ec72af73c77b60598d3865a57794(SB) 0x002f 00047 (once.go:10) FUNCDATA $2, gclocals·f921db378992a411b04a03b038505262(SB) 0x002f 00047 (once.go:11) PCDATA $0, $1 0x002f 00047 (once.go:11) PCDATA $1, $0 0x002f 00047 (once.go:11) MOVQ "".o+184(SP), AX 0x0037 00055 (once.go:11) TESTB AL, (AX) 0x0039 00057 (once.go:11) PCDATA $0, $0 0x0039 00057 (once.go:11) MOVL 8(AX), AX 0x003c 00060 (once.go:11) MOVL AX, ""..autotmp_2+20(SP) 0x0040 00064 (once.go:11) CMPL AX, $1 0x0043 00067 (once.go:11) JEQ 71 0x0045 00069 (once.go:11) JMP 93 0x0047 00071 (once.go:12) PCDATA $1, $1 0x0047 00071 (once.go:12) XCHGL AX, AX 0x0048 00072 (once.go:12) CALL runtime.deferreturn(SB) 0x004d 00077 (once.go:12) MOVQ 168(SP), BP 0x0055 00085 (once.go:12) ADDQ $176, SP 0x005c 00092 (once.go:12) RET 0x005d 00093 (once.go:14) PCDATA $1, $0 0x005d 00093 (once.go:14) JMP 95 0x005f 00095 (once.go:14) PCDATA $0, $1 0x005f 00095 (once.go:14) MOVQ "".o+184(SP), AX 0x0067 00103 (once.go:14) TESTB AL, (AX) 0x0069 00105 (once.go:14) MOVQ AX, ""..autotmp_4+160(SP) 0x0071 00113 (once.go:14) PCDATA $0, $0 0x0071 00113 (once.go:14) MOVQ AX, (SP) 0x0075 00117 (once.go:14) CALL sync.(*Mutex).Lock(SB) 0x007a 00122 (once.go:15) PCDATA $0, $1 0x007a 00122 (once.go:15) MOVQ "".o+184(SP), AX 0x0082 00130 (once.go:15) TESTB AL, (AX) 0x0084 00132 (once.go:15) PCDATA $0, $0 0x0084 00132 (once.go:15) PCDATA $1, $2 0x0084 00132 (once.go:15) MOVQ AX, ""..autotmp_5+152(SP) 0x008c 00140 (once.go:15) MOVL $8, ""..autotmp_7+24(SP) 0x0094 00148 (once.go:15) PCDATA $0, $1 0x0094 00148 (once.go:15) LEAQ sync.(*Mutex).Unlock·f(SB), AX 0x009b 00155 (once.go:15) PCDATA $0, $0 0x009b 00155 (once.go:15) MOVQ AX, ""..autotmp_7+48(SP) 0x00a0 00160 (once.go:15) PCDATA $0, $1 0x00a0 00160 (once.go:15) PCDATA $1, $0 0x00a0 00160 (once.go:15) MOVQ ""..autotmp_5+152(SP), AX 0x00a8 00168 (once.go:15) PCDATA $0, $0 0x00a8 00168 (once.go:15) MOVQ AX, ""..autotmp_7+72(SP) 0x00ad 00173 (once.go:15) PCDATA $0, $1 0x00ad 00173 (once.go:15) LEAQ ""..autotmp_7+24(SP), AX 0x00b2 00178 (once.go:15) PCDATA $0, $0 0x00b2 00178 (once.go:15) MOVQ AX, (SP) 0x00b6 00182 (once.go:15) CALL runtime.deferprocStack(SB) //把函数压入栈中 0x00bb 00187 (once.go:15) TESTL AX, AX 0x00bd 00189 (once.go:15) JNE 368 0x00c3 00195 (once.go:15) JMP 197 0x00c5 00197 (once.go:16) PCDATA $0, $1 0x00c5 00197 (once.go:16) MOVQ "".o+184(SP), AX 0x00cd 00205 (once.go:16) TESTB AL, (AX) 0x00cf 00207 (once.go:16) PCDATA $0, $0 0x00cf 00207 (once.go:16) CMPL 8(AX), $0 0x00d3 00211 (once.go:16) JEQ 218 0x00d5 00213 (once.go:16) JMP 366 0x00da 00218 (once.go:17) PCDATA $0, $1 0x00da 00218 (once.go:17) PCDATA $1, $3 0x00da 00218 (once.go:17) MOVQ "".o+184(SP), AX 0x00e2 00226 (once.go:17) TESTB AL, (AX) 0x00e4 00228 (once.go:17) ADDQ $8, AX 0x00e8 00232 (once.go:17) PCDATA $0, $0 0x00e8 00232 (once.go:17) PCDATA $1, $4 0x00e8 00232 (once.go:17) MOVQ AX, ""..autotmp_6+144(SP) 0x00f0 00240 (once.go:17) MOVL $16, ""..autotmp_8+80(SP) 0x00f8 00248 (once.go:17) PCDATA $0, $1 0x00f8 00248 (once.go:17) LEAQ sync/atomic.StoreUint32·f(SB), AX 0x00ff 00255 (once.go:17) PCDATA $0, $0 0x00ff 00255 (once.go:17) MOVQ AX, ""..autotmp_8+104(SP) 0x0104 00260 (once.go:17) PCDATA $0, $1 0x0104 00260 (once.go:17) PCDATA $1, $3 0x0104 00260 (once.go:17) MOVQ ""..autotmp_6+144(SP), AX 0x010c 00268 (once.go:17) PCDATA $0, $0 0x010c 00268 (once.go:17) MOVQ AX, ""..autotmp_8+128(SP) 0x0114 00276 (once.go:17) MOVL $1, ""..autotmp_8+136(SP) 0x011f 00287 (once.go:17) PCDATA $0, $1 0x011f 00287 (once.go:17) LEAQ ""..autotmp_8+80(SP), AX 0x0124 00292 (once.go:17) PCDATA $0, $0 0x0124 00292 (once.go:17) MOVQ AX, (SP) 0x0128 00296 (once.go:17) CALL runtime.deferprocStack(SB) //把函数压入栈中 0x012d 00301 (once.go:17) TESTL AX, AX 0x012f 00303 (once.go:17) JNE 344 0x0131 00305 (once.go:17) JMP 307 0x0133 00307 (once.go:18) PCDATA $0, $2 0x0133 00307 (once.go:18) PCDATA $1, $1 0x0133 00307 (once.go:18) MOVQ "".f+192(SP), DX 0x013b 00315 (once.go:18) MOVQ (DX), AX 0x013e 00318 (once.go:18) PCDATA $0, $0 0x013e 00318 (once.go:18) CALL AX 0x0140 00320 (once.go:18) JMP 322 0x0142 00322 (once.go:20) XCHGL AX, AX 0x0143 00323 (once.go:20) CALL runtime.deferreturn(SB) 0x0148 00328 (once.go:20) MOVQ 168(SP), BP 0x0150 00336 (once.go:20) ADDQ $176, SP 0x0157 00343 (once.go:20) RET 0x0158 00344 (once.go:17) XCHGL AX, AX 0x0159 00345 (once.go:17) CALL runtime.deferreturn(SB) //先调用后入栈的,即atomic.StoreUint32(&o.done, 1) 0x015e 00350 (once.go:17) MOVQ 168(SP), BP 0x0166 00358 (once.go:17) ADDQ $176, SP 0x016d 00365 (once.go:17) RET 0x016e 00366 (once.go:16) PCDATA $0, $-2 0x016e 00366 (once.go:16) PCDATA $1, $-2 0x016e 00366 (once.go:16) JMP 322 0x0170 00368 (once.go:15) PCDATA $0, $0 0x0170 00368 (once.go:15) PCDATA $1, $1 0x0170 00368 (once.go:15) XCHGL AX, AX 0x0171 00369 (once.go:15) CALL runtime.deferreturn(SB) //再调用先入栈的,即o.m.Unlock() 0x0176 00374 (once.go:15) MOVQ 168(SP), BP 0x017e 00382 (once.go:15) ADDQ $176, SP 0x0185 00389 (once.go:15) RET 0x0186 00390 (once.go:15) NOP 0x0186 00390 (once.go:10) PCDATA $1, $-1 0x0186 00390 (once.go:10) PCDATA $0, $-1 0x0186 00390 (once.go:10) CALL runtime.morestack_noctxt(SB) 0x018b 00395 (once.go:10) JMP 0
如果一个函数中有多个defer语句,它们会以LIFO(后进先出)的顺序执行。哪怕函数或某个延迟调用发生错误,这些调用依旧会被执。
https://www.cnblogs.com/nulige/p/10233001.html
更多相关defer的请参考: https://www.cnblogs.com/xinliangcoder/p/12079135.html