其他分享
首页 > 其他分享> > go函数调用栈,Golang 实现结构体数组按多字段排序,panic: test timed out after 30s

go函数调用栈,Golang 实现结构体数组按多字段排序,panic: test timed out after 30s

作者:互联网

函数调用栈

-gcflags

使用go build -gcflags -S once.go也可以得到汇编代码

-objdump

最终的机器码的汇编可以通过go tool objdump生成。

https://mp.weixin.qq.com/s/zcqzarXMJrDUY5DLXZXY1Q

我们按照编程语言的语法定义的函数,会被编译器编译为一堆堆机器指令写入可执行文件。程序执行时可执行文件被加载到内存,这些机器指令对应到虚拟地址空间中,位于代码段

如果在一个函数中调用另一个函数,编译器就会对应生成一条call指令,程序执行到这条指令时,就会跳转到被调用函数入口处开始执行,而每个函数的最后都有一条ret指令,负责在函数结束后跳回到调用处,继续执行。

1.函数栈桢

函数执行时需要有足够的内存空间,供它存放局部变量、参数等数据,这段空间对应到虚拟地址空间的栈。

分配给函数的栈空间被称为“函数栈帧”,Go语言中函数栈帧布局是这样的,先是调用者栈基地址,然后是函数的局部变量,最后是被调用函数的返回值和参数

BP of callee和SP of callee标识被调用函数执行时,栈基寄存器和栈指针寄存器指向的位置,但是注意“BP of caller”不一定会存在,有些情况下可能会被优化掉,也有可能是平台不支持。我们只关注局部变量和参数、返回值的相对位置就好

Go语言中,函数栈帧是一次性分配的,也就是在函数开始执行的时候分配足够大的栈帧空间一次性分配函数栈帧的主要原因是避免栈访问越界,其实,对于栈消耗较大的函数,go语言的编译器还会在函数头部插入检测代码,如果发现需要进行“栈增长”,就会另外分配一段足够大的栈空间,并把原来栈上的数据拷过来,原来的这段栈空间就被释放了。

总结:

2.传参


func swap(a,b int) {
    a,b = b,a
}
    
func main() {
    a,b := 1,2
    swap(a,b)
    println(a,b)  //1,2
}

交换失败原因:函数没有返回值;交换a、b两个局部变量,实际上交换的是参数空间

Go语言中传参都是值拷贝。

改成整型指针就交换成功

func swap(a,b *int) {
    *a,*b = *b,*a
}
    
func main() {
    a,b := 1,2
    swap(&a,&b)
    println(a,b)  //2,1
}

swap要交换的是这两个参数指针指向的数据,也就是局部变量空间这里的a和b。

3.返回值

func incr(a int) (b int) {
    defer func(){
        a++
        b++
    }()
    
    a++
    return a
}
func main(){
    var a,b int
    b = incr(a)
    println(a,b) //0,2
}

4.函数跳转与返回

程序执行时 CPU用特定寄存器存储运行时栈基与栈指针,同时也有指令指针寄存器用于存储下一条要执行的指令地址


func A(){
    a,b := 1,2
    B(a,b)
    return
}
func B(c,d int){
    println(c,d)
    return
}

简单来说,函数通过call指令实现跳转,而每个函数开始时会分配栈帧,结束前又释放自己的栈帧,ret指令又会把栈恢复到call之前的样子,通过这些指令的配合最终实现了函数跳转与返回。

方式二:

文件在终端打开安装下面的格式注意 - timeout 130s

 go test -timeout 130s -run ^TestBackLight$ neuron/function/visca/blp -v -count=1

Golang 实现结构体数组按多字段排序

https://richerdyoung.com/p/118.html

实例1

package main

import (
  "fmt"
  "sort"
)

type Obj struct {
  Var      string `json:"var"`
  Mtime    int    `json:"mtime"`
  Orderval int    `json:"orderval"`
}

type List []Obj

func (p List) Len() int { // 重写 Len() 方法
  return len(p)
}

// 此处排序是从大到小的, 如果想升序,可以把此方法里的 判定 改为 相反的判定即可
func (p List) Less(i, j int) bool { // 重写 Less() 方法
  if p[i].Orderval > p[j].Orderval {
    return true
  }
  if p[i].Orderval < p[j].Orderval {
    return false
  }
  return p[i].Orderval > p[j].Orderval
}

func (p List) Swap(i, j int) { // 重写 Swap() 方法
  p[i], p[j] = p[j], p[i]
}

func (p *List) Sort() {
  sort.Sort(p)
}

func main() {
  s := List{{"f", 1595144638, 4}, {"d", 1595144646, 2}, {"a", 1595144648, 8}, {"t", 1595144648, 5}, {"e", 1595144650, 3}}
  fmt.Println(s)
  s.Sort()
  fmt.Println(s)

}

// 如果想使用传入的方法来写,可以把main 方法 的写法改为下边这个
//func toSortAsc(UserList []Obj)[]Obj{
//    s := List{}
//    for _,v := range UserList{
//        s = append(s,v)
//    }
//    s.Sort()
//    return s
//}


实例2

package main

import (
    "fmt"
    "sort"
)

type Instance struct {
    Domain     string   `json:"domain"`
    Ip         string   `json:"ip"`
    Containers []string `json:"containers,omitempty"`
}

func main() {
    instances := make([]*Instance, 0, 10)

    i1 := &Instance{}
    i1.Domain = "zhap"
    i1.Ip = "1"
    instances = append(instances, i1)

    i2 := &Instance{}
    i2.Domain = "abc"
    i2.Ip = "2"
    instances = append(instances, i2)

    i3 := &Instance{}
    i3.Domain = "mid"
    i3.Ip = "3"
    instances = append(instances, i3)

    fmt.Println("排序前 ")
    for _, v := range instances {
        fmt.Println(*v)
    }
    sort.Slice(instances, func(i, j int) bool {
        return instances[i].Domain < instances[j].Domain
    })
    fmt.Println("排序后 ")
    for _, v := range instances {
        fmt.Println(*v)
    }
}

panic: test timed out after 30s

方式一:

方式二:

文件在终端打开安装下面的格式注意 - timeout 130s

 go test -timeout 130s -run ^TestBackLight$ neuron/function/visca/blp -v -count=1

标签:30s,return,函数,int,fmt,after,函数调用,instances,func
来源: https://www.cnblogs.com/ling11/p/16318243.html