https://golang.design/go-questions/sched/init/
(任何一个.go文件的)init都先于main执行。
main.go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package main
import ( "fmt" "initt/tools" )
func main() {
fmt.Println("main start~~~")
fmt.Println(tools.Int2Str(21333333333))
}
|
tools/toolFunc.go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package tools
import ( "fmt" "strconv" )
func init() {
fmt.Println("init start...")
}
func Int2Str(arg int) string {
return strconv.Itoa(arg) }
|
运行 go run main.go,结果为:
1 2 3
| init start... main start~~~ 21333333333
|
Shit Mountain遇险记:
(任何一个.go文件的)init都先于main执行。
某陈年老代码,不遵循单一入口,各种中间件的初始化不放在main.go里,而是很多package都有一个init(如 有一个叫做storage文件夹,用来放各种存储。该文件夹下有一个init())…
这样做平时没什么,有一天,需要给mysql,redis,kafka,httpclient等加一个哨兵监控。 需要在mysql,redis初始化时,拿到哨兵的实例,用其中某个collector作为参数传递。。
这个监控的sdk,按常理显然应该在main.go里初始化,而各个包的init,先于main.main执行,于是在在mysql,redis等初始化时,调用哨兵显然为nil。。
最后通过hook,或全局变量予以解决。。当时也有考虑,在init()满天飞的场景下,能否确定哪个init()最先执行? 或者能否也写一个init()初始化哨兵监控 并保证其最先执行?
这其实涉及到runtime ….(待写)
爽哥于深夜
pointer.go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package main
import ( "fmt" )
func main() { var p **int var i int = 10 var p1 *int = &i fmt.Println("p1=", p1)
p = &p1 fmt.Println("p=", p) }
|
go build -gcflags=all="-N -l" pointer.go
(go build -gcflags=all=”-N -l” 禁用编译器优化和内联函数,在研究runtime时非常有必要 )
Golang init() 函数
Go:神奇的init函数
Go语言goroutine调度器初始化
https://7byte.github.io/2017/05/20/golangPackageInit/
https://studygolang.com/articles/6464
【Golang源码分析】golang的启动原理
Golang后台单元测试实践
基于Golang的云原生日志采集服务设计与实践
Golang 并发编程核心篇 —— 内存可见性
GODEBUG=INITTRACE=1 ./dashen
https://stackoverflow.com/questions/24790175/when-is-the-init-function-run
https://play.golang.org/p/9P-LmSkUMKY
https://xie.infoq.cn/article/7baab69fe385d0c6a1b35fa32
https://zboya.github.io/post/go_scheduler/
https://learnku.com/go/t/47135
https://www.bookstack.cn/read/qcrao-Go-Questions/spilt.10.GC-GC.md
https://blog.leonard.wang/archives/inittask
Init()灵不灵?
不灵!只认init()
golang init的顺序你清楚吗
1 2 3 4 5 6 7 8 9 10 11
| 是的,我可以解释一下 Go 中 init 函数的顺序。
在 Go 中,init 函数用于初始化包和程序。当一个包被导入时,Go 运行该包中所有的 init 函数。当一个程序启动时,Go 运行主包(即 main 包)中的 init 函数。
init 函数的执行顺序遵循以下规则:
首先会执行依赖包(被当前包导入的其他包)中的 init 函数,且每个包的 init 函数只会执行一次。
如果当前包有多个 init 函数,它们会按照源代码中的顺序依次执行。
总之,Go 保证 init 函数的执行顺序是正确的,开发者无需手动控制 init 函数的执行顺序。
|
我想把整个项目中所有init的执行顺序打印出来?如何实现?
你可以通过反射(reflection)获取一个包中所有的函数,并筛选出所有以 init 命名的函数,然后按照顺序执行它们并记录执行的顺序。以下是一个示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package main
import ( "fmt" "reflect" "sort" )
func main() { pkg := "example.com/mypackage" funcs := []string{}
pkgFuncs := reflect.ValueOf(pkg).Elem().FieldByName("init").FieldByName("i").FieldByName("funcs") for i := 0; i < pkgFuncs.Len(); i++ { f := pkgFuncs.Index(i) funcName := f.FieldByName("name").String() if funcName == "init" { continue } funcs = append(funcs, funcName) }
sort.Strings(funcs)
fmt.Println("Init functions order:") for _, funcName := range funcs { fmt.Println(funcName) fn := reflect.ValueOf(pkg).MethodByName(funcName) fn.Call(nil) } }
|
请将 example.com/mypackage 替换为你的包名,然后运行该代码,它将输出所有 init 函数的执行顺序。注意,这个方法只适用于在当前可执行文件中使用的包,如果你想打印整个项目中所有包的 init 函数的执行顺序,你需要在每个包的代码中使用类似的方法并手动整合。
我就是想把整个项目的打印出来?要怎样实现
要实现打印整个项目中所有包的 init 函数的执行顺序,你需要对每个包都使用类似的方法并手动整合它们。
以下是一个示例代码,可以打印整个项目中所有包的 init 函数的执行顺序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| package main
import ( "fmt" "reflect" "sort" "strings" )
func main() { initOrder := make(map[string]int) packages := make(map[string]bool) var scan func(pkg string)
scan = func(pkg string) { if packages[pkg] { return } packages[pkg] = true
pkgFuncs := reflect.ValueOf(pkg).Elem().FieldByName("init").FieldByName("i").FieldByName("funcs") for i := 0; i < pkgFuncs.Len(); i++ { f := pkgFuncs.Index(i) funcName := f.FieldByName("name").String() if funcName == "init" { continue } initOrder[pkg+"."+funcName] = len(initOrder) }
pkgDeps := reflect.ValueOf(pkg).Elem().FieldByName("imports") for i := 0; i < pkgDeps.Len(); i++ { depPkg := pkgDeps.Index(i).String() if !strings.HasPrefix(depPkg, "vendor/") { scan(depPkg) } } }
scan(".")
type initFunc struct { pkg string name string } funcs := make([]initFunc, len(initOrder)) for k, v := range initOrder { pkgName, funcName := strings.Split(k, ".")[0], strings.Split(k, ".")[1] funcs[v] = initFunc{pkgName, funcName} }
fmt.Println("Init functions order:") for _, f := range funcs { fmt.Printf("%s.%s\n", f.pkg, f.name) } }
|
该代码使用递归方式扫描项目中的所有包,并记录每个包的 init 函数的执行顺序。最后,它按照执行顺序打印出每个包中所有 init 函数的名称。请注意,该代码将忽略 vendor 目录下的包,如果你想包括这些包,可以将代码中的相关部分进行修改。
如何规避滥用init(),如何解决一些初始化配置等的需求?
很多知名项目中,都有这样使用。。比如k8s的第一个版本
原文链接: https://dashen.tech/2022/05/19/init-的执行顺序-Go-scheduler的初始化过程/
版权声明: 转载请注明出处.