從Goroot的代碼出發,裏面有很多代碼非常複雜,一點點看吧。最重要的概念就是runtime,golang的程序都是在runtime的基礎上運行的(除了與底層直接交互的syscall)。
在$goroot/pkg/runtime/中有三個文件非常重要:
proc.c
stack.h
runtime.h
在runtime.h中你能看到許多的數據結構和接口
這裏的數據結構就是go中的各種特定的結構對應的底層實現,比如slice:
1
2
3
4
5
6
7
|
struct
Slice
{
// must not move anything
byte
* array;
// actual data
uint32 len;
// number of elements
uint32 cap;
// allocated number of elements
};
|
其中還有兩個重要的結構:
G代表的是goroutine。開啓一個goroutine實際就是實例化一個G
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程序的啓動流程是:
在這個函數內做了許多預操作
(主要是有一個環境變量GOMAXPROCS,你可以使用runtime.GOMAXPROCS(int) 或者直接設置環境變量$GOMAXPROCS改變程序使用的CPU數量)
在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程序的,有兩種方法:
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package main
/*
#include <stdlib.h>
*/
import
"C"
import
"fmt"
func main(){
fmt.Println(
int
(C.random()))
}
func Seed(i
int
) {
C.srandom(C.
uint
(i))
}</stdlib.h>
|
運行
使用起來非常簡單,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的標準庫,只能引用自定義的頭文件。這種方式很少使用,基本只需要知道一下就好了。