Go程序的初始化和执行总是通过main.main开始的,如果是其他package.main那么这个main函数就是一个普通函数,不能作为初始化和执行的入口。
在程序初始化的时候,如果在main包中导入了其他的包,则会按照顺序将它们包含进main包里(这里的导入顺序依赖具体实现,一般可能是以文件名或包路径名的字符串顺序导入)。
如果某个包被多次导入的话,在执行的时候只会导入一次。
当一个包被导入时,如果它还导入了其它的包,则先将其它的包包含进来,然后创建和初始化这个包的常量和变量。
然后就是调用包里的init函数,如果一个包有多个init函数的话,实现可能是以文件名的顺序调用,同一个文件内的多个init则是以出现的顺序依次调用(init不是普通函数,可以定义有多个,所以不能被其它函数调用)。注:需谨慎并尽可能少使用init()
最终,在main包的所有包常量、包变量被创建和初始化,并且init函数被执行后,才会进入main.main函数,程序开始正常执行。
下图是Go程序函数启动顺序的示意图:
要注意的是,在main.main函数执行之前所有代码都运行在同一个Goroutine中,也是运行在程序的主系统线程中。如果某个init函数内部用go关键字启动了新的Goroutine的话,新的Goroutine和main.main函数是并发执行的。
因为所有的init函数和main函数都是在主线程完成,它们也是满足顺序一致性模型的。
参考连接:https://chai2010.gitbooks.io/advanced-go-programming-book/content/ch1-basic/ch1-05-mem.html