当前位置: 首页 > 后端技术 > PHP

快看一下有趣的--go-指令

时间:2023-03-30 02:03:13 PHP

原文地址:简单看一下有趣的//go:指令咦,为什么有的方法上面总是写着//go:之类的指令。他们到底是为了什么?今天我们一起揭开它们的面纱,简单给大家介绍一下,它们分别负责什么go:linkname//go:linknamelocalnameimportpath.name该指令指示编译器使用importpath.name作为源代码中声明的localname的目标文件变量或函数的符号名称。但是因为这个指令,类型系统和包模块化可以被打破。因此,只有在引用了unsafe包的情况下才能使用。简单的说,importpath.name是localname的符号别名,编译器会实际调用localname。但前提是使用unsafe包使用casetime/time.go...funcnow()(secint64,nsecint32,monoint64)runtime/timestub.goimport_"unsafe"//forgo:linkname//go:linknametime_nowtime.nowfunctime_now()(secint64,nsecint32,monoint64){sec,nsec=walltime()returnsec,nsec,nanotime()-startNano}在这种情况下见time.now,它没有具体的实现。乍一看可能会令人困惑。这时候建议大家全局搜索一下源码,会发现其实是在runtime.time_now中。通过前面的使用说明可以知道,在runtime包中,我们声明了time_now方法是time.now的符号别名。并在文件头引入unsafe以满足前提条件go:noescape//go:noescape这条指令指定了下一个有语句但没有body(意思是实现可能不是Go)的函数,不允许编译器对其进行逃逸分析。在这种情况下,该指令用于内存分配优化。因为编译器默认会进行逃逸分析,它会通过规则来判断一个变量是分配在堆上还是分配在栈上。但一切都出乎意料。虽然有些函数逃脱了分析,但它们存储在堆上。但对我们来说,这很特别。我们可以使用go:noescape指令强制编译器将其分配到函数栈上。case//memmovecopynbytesfrom"from"to"to".//inmemmove_*.s//go:noescapefuncmemmove(to,fromunsafe.Pointer,nuintptr)让我们观察这个案例,它满足共同的特征这条指令。如下:memmove_*.s:只有语句,没有正文。它的主体是底层汇编实现的memmove:function函数,在栈上的处理性能会更好简单的说,这个函数跳过栈溢出的检查情况该指令告诉编译器在遇到写屏障时产生错误,并且允许递归。即这个函数调用的其他函数如果有写屏障也会报错。简单的说就是对writebarriers的处理,防止其死循环的情况//go:nowritebarrierrecfuncgcFlushBgCredit(scanWorkint64){...}go:yeswritebarrierrec//go:yeswritebarrierrec这条指令和go:nowritebarrierrec相反,go:nowritebarrierrec指令函数中标记,遇到写屏障会产生错误。而当编译器遇到go:yeswritebarrierrec指令时,就会停止case(b[]byte,iint)byte{returnb[i]}我们来看这个案例,直接通过索引获取值,逻辑比较简单。如果不加go:noinline,编译器会优化inline。显然,内联有利也有弊。这条指令就是提供这种特殊的处理go:norace//go:norace这条指令表示禁止竞态检测。另一种常见的形式是在启动时执行gorun-race,可以检测应用中是否存在双向数据竞争。非常有用的案例//go:noracefuncforkAndExecInChild(argv0*byte,argv,envv[]*byte,chroot,dir*byte,attr*ProcAttr,sys*SysProcAttr,pipeint)(pidint,errErrno){...}go:notinheap//go:notinheap该指令常用于类型声明中,表示该类型不允许从GC堆中申请内存。它通常在运行时用于较低级别的内部结构,避免调度程序和内存分配中的写障碍。Canimproveperformancecase//notInHeapisoff-heapmemoryallocatedbyalower-levelallocator//likesysAllocorpersistentAlloc.////一般情况下,最好使用标记为go:notinheap的真实类型,//但这个服务作为通用类型,用于//不可能的情况(例如在分配器中)。////go:notinheaptypenotInHeapstruct{}总结在本文中我们简要介绍了一些常见的指令集,我推荐它以供理解.一般我们不会用,因为你的瓶颈可能更多在你自己的应用上,但是理解这一点有助于你理解底层源码和运行机制。如果想深入,可以看我给的参考链接:)参考HACKINGCommandcompile