In-depth understanding of Golang: defer, recover, panic, reflect

cgo

Calling C code in Go:

/*
int sum(int a, int b) {
  return a+b;
}
*/
import "C"

func main() {
    
    
    println(C.sum(1, 1))
}
  • cgo is a technology that allows the go language to call C methods
  • cgo needs the cooperation of go scheduler and coroutine stack
  • cgo is generally used when the go implementation cannot be found
  • cgo does not improve performance and is a temporary solution

defer

defer: The statement after defer will be executed before the function exits.

Ideas:

  1. The coroutine records defer information and is called when the function exits
  2. Compile the defer code directly into the end of the function

1.1 Allocation on the heap

  • Used before 1.12
  • allocate a heapsched.deferpool
  • When encountering a defer statement, put the information indeferpool
  • When the function returns, deferpoolfetch and execute from

deferpoolDocumented on thread struct p:

type p struct {
    
    
    // ...
    deferpool    []*_defer // pool of available defer structs (see panic.go)
    deferpoolbuf [32]*_defer
    // ...
}

1.2 Allocation on the stack

  • Appeared after 1.13
  • When encountering a defer statement, put the information on the stack
  • When the function returns, it is taken from the stack and executed
  • Only one defer information can be saved

2.1 Open coding

  • Appeared after 1.14
  • If the defer statement can be determined at compile time, rewrite the user code directly, and put the defer statement at the end of the function
func main() {
    
    
    defer fmt.Println("defer1")
    defer fmt.Println("defer2")
    fmt.Println("main")
}

recover、panic

panic

  • panic will throw an error
  • Terminate the coroutine running
  • Crash the entire Go program
func main() {
    
    
    go func() {
    
    
        panic("panic")
        fmt.Println("do")
    }()
    fmt.Println("main")
    time.Sleep(1 * time.Second)
    /*
    main
    panic: panic
    */
}

panic + defer

  • Panic will execute all registered defers of this coroutine before exiting the coroutine
  • Will not execute defer of other coroutines
func main() {
    
    
    defer fmt.Println("defer1")

    go func() {
    
    
        defer fmt.Println("defer2")
        panic("panic1")
        fmt.Println("do")
    }()

    fmt.Println("main")
    time.Sleep(1 * time.Second)

    /**
    main
    defer2
    panic: panic1
    */
}

panic + defer + recover

Executing recover in defer can save the coroutine

  • If recover is involved, defer will use heap allocation
  • In case of a panic, the panic will take out the defer statement from the deferpool and execute it
  • Calling recover in defer can terminate the panic process
func main() {
    
    
    defer fmt.Println("defer1")

    go func(){
    
    
         defer func() {
    
    
            if r := recover(); r != nil {
    
    
                fmt.Println("Recovered. Error: ", r)
            }
        }()
        panic("panic1")
        fmt.Println("do")
    }()
    fmt.Println("main")

    time.Sleep(1 * time.Second)

    /**
    main
    Recovered. Error:  panic1
    defer1
    */
}

reflection reflect

func main() {
    
    
 s := "moody"

 stype := reflect.TypeOf(s)
 fmt.Println("TypeOf s:", stype)

 svalue := reflect.ValueOf(s)
 fmt.Println("ValueOf s:", svalue)
}

reflect object to object

metadata

  • Metadata is "data about data"
  • Represent the type of an object as a data type
  • Represent the value of an object as a data type
func main() {
    
    
    s := "go"

    // 对象的类型
    // 把对象的类型表示成一个接口
    stype := reflect.TypeOf(s)
    fmt.Println("TypeOf s:", stype) // TypeOf s: string

    // 对象的值
    // 把对象的值表示成一个接口
    svalue := reflect.ValueOf(s)
    fmt.Println("ValueOf s:", svalue) // ValueOf s: go

    s2 := svalue.Interface().(string)

    // 
    fmt.Println("s2:", s2) // s2: go
}
  • runtime.eface is the runtime representation of an empty interface
  • runtime.emptyinterface is the reflection package's representation of the empty interface
  • When the object is converted to a reflection object, the compiler will convert the input parameter to eface in advance
  • When reflecting object to object, restore data according to address and type

reflective call method

Call methods through reflection to achieve decoupling of user methods and frameworks

func MyAdd(a, b int) int {
    
     return a + b }

func CallAdd(f func(a int, b int) int) {
    
    
    v := reflect.ValueOf(f)
    if v.Kind() != reflect.Func {
    
    
        return
    }
    argv := make([]reflect.Value, 2)
    argv[0] = reflect.ValueOf(1)
    argv[1] = reflect.ValueOf(1)

    result := v.Call(argv)
    fmt.Println(result[0].Int())
}

func main() {
    
    
    CallAdd(MyAdd)
}

Guess you like

Origin blog.csdn.net/by6671715/article/details/131536451