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