go defer

     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
上一篇:js时间线及defer async


下一篇:GO语言学习笔记(七、function)