從Goroot的代碼出發,里面有很多代碼非常復雜,一點點看吧。最重要的概念就是runtime,golang的程序都是在runtime的基礎上運行的(除了與底層直接交互的syscall)。
Runtime
在$goroot/pkg/runtime/中有三個文件非常重要:
proc.c
stack.h
runtime.h
在runtime.h中你能看到許多的數據結構和接口
這里的數據結構就是go中的各種特定的結構對應的底層實現,比如slice:
struct Slice { // must not move anything byte* array; // actual data uint32 len; // number of elements uint32 cap; // allocated number of elements };
其中還有兩個重要的結構:
G
G代表的是goroutine。開啟一個goroutine實際就是實例化一個G
M
M代表的是Machine。M中存放go程序和機器CPU交互的數據結構
比如一個雙核CPU,在主routine外開啟了4個goroutine,那么實際上就有2個M結構,6個G結構(1個是主routine,4個開啟的routine,最后一個是閑置的routine)
runtime和C標准庫起的作用是一樣的。都是為了語言的跨平台性。runtime可以運行在Windows和Unix平台,可以運行在Intel或ARM處理器上。
一個go程序都附帶一個Runtime,runtime負責與底層操作系統交互。
這篇文章給了一個清晰的runtime概念:http://pastebin.com/LEsB8FVW
啟動流程
回到$goroot/pkg/runtime/proc.c
里面這么個注釋:
// The bootstrap sequence is:
//
// call osinit
// call schedinit
// make & queue new G
// call runtime·mstart
//
// The new G calls runtime·main.
明確告訴我們go程序的啟動流程是:
1 調用osinit,操作系統級別的初始化
2 調用runtime·schedinit
在這個函數內做了許多預操作
獲取程序運行參數
獲取程序環境變量
(主要是有一個環境變量GOMAXPROCS,你可以使用runtime.GOMAXPROCS(int) 或者直接設置環境變量$GOMAXPROCS改變程序使用的CPU數量)
3 調用runtime·mstart啟動M
4 調用runtime·main
在runtime.main中有這么兩行:
main·init(); //調用main包中的init函數
main·main(); //調用main包中的main函數
用gdb調試看trace看到調用棧
關於啟動流程推薦一下這篇文章:http://www.cnblogs.com/genius0101/archive/2012/04/16/2447147.html
go中調用C程序
go中是可以調用C程序的,有兩種方法:
1 go程序使用import "C"
2 使用文件.goc(以前也叫做cgo)
第一種方法
例子:
package main /* #include*/ import "C" import "fmt" func main(){ fmt.Println(int(C.random())) } func Seed(i int) { C.srandom(C.uint(i)) }
運行
使用起來非常簡單,import "C"之后就有一個全局變量大寫C就包含了C庫中的函數, include的c庫作為注釋放在import "C"上面
更多可以參考:
http://golang.org/doc/articles/c_go_cgo.html
第二種方法
直接創建goc文件,goc文件是C和go混合編寫的文件
參照$goroot/src/pkg/runtime/syscall_windows.goc
這種方式不允許include C的標准庫,只能引用自定義的頭文件。這種方式很少使用,基本只需要知道一下就好了。
參考文章
我之前寫了文章把所有golang的底層相關文章列出來了
http://www.cnblogs.com/yjf512/archive/2012/07/17/2595689.html
如果有更多的好資料麻煩各位貼出來下~