每一個Go程序包含一個名爲main的包以及其main函數,在初始化後,程序從main開始執行,避免引入不使用的包(編譯不經過)編程
基本數據類型數組
bool, byte int,int8,int16,int32,int64 uint8,uint16,uint32,uint64 float32,float64(沒有float類型) string
變量賦值性能優化
var a a = 12 a := 12 a,b :=12,23
常量賦值服務器
const( a = iota b )
循環只有 for併發
for i:=0;i<10;i++{ do Something... } for{ //至關於while(true){} } for _,v:= range list{ //range用法返回list數組或者列表的k,v兩個值(k數組索引從0開始,v值) fmt.Print("%s", v) }
選擇 if 和 switch函數
a := 1 b := 1 if a+b > 2 { // 注:if(條件不帶括號,且左大括號與if保持同行) }
完整demo 大白加大白等於白胖胖.求大,白,胖各是數字多少?性能
package main import ( "fmt" "strconv" ) /* 大白加大白等於白胖胖.求大,白,胖各是數字多少? */ func main() { for d := 1; d < 10; d++ { for b := 1; b < 10; b++ { for p := 1; p < 10; p++ { daBai, _ := strconv.Atoi(strconv.Itoa(d) + strconv.Itoa(b)) // fmt.Println("大白", daBai) baiPangPang, _ := strconv.Atoi(strconv.Itoa(b) + strconv.Itoa(p) + strconv.Itoa(p)) // fmt.Println("白胖胖", baiPangPang) if daBai+daBai == baiPangPang { fmt.Println("-------------------大 白 胖--------------------") fmt.Printf("大 = %d, 白 = %d, 胖 = %d\n", d, b, p) fmt.Println("白胖胖: ", baiPangPang) } } } } }
數組聲明:ArrayType = "[" ArrayLength "]" ElementType .學習
var a [32] int var b [3][5] int
(1)數組是值類型。將一個數組賦值給另外一個,會拷貝全部的元素.優化
(2) 若是你給函數傳遞一個數組,其將收到一個數組的拷貝,而不是它的指針.ui
(3)數組的大小是其類型的一部分,類型[10]int和[20]int是不一樣的。數組長度在聲明後,就不可更改.
切片聲明:SliceType = "[" "]" ElementType .
var a []int
(1)沒有初始化的slice爲nil.
(2)切片(slice)對數組進行封裝,實際上,切片能夠當作大小能夠動態變化的數組.
(3)Go中大多數的數組編程都是經過切片完成,而不是簡單數組.
通常來講,有兩種方式來初始化切片:
//經過數組方式 var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} var mySlice []int = myArray[:5] //make方式 make([]T, length, capacity)
Goroutine和channel是Go在「併發」方面兩個核心feature。
Channel是goroutine之間進行通訊的一種方式,go所提倡的"應該以通訊做爲手段來共享內存"的最直接體現。
Channel聲明:
ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
var ch chan int
var ch1 chan<- int //ch1只能寫
var ch2 <-chan int //ch2只能讀
//make初始化
putnamechan := make(chan string, 100) //帶緩衝
關鍵字go,啓用Goroutine的惟一途徑
//同時向五我的打招呼 func main(){ names := []string{"Eric","Tom","Jack","Jim"} for _,name:= range names{ go func(){ fmt.Printf("Hello,%s.\n",name) }() } runtime.Gosched() }
Go的調度器內部有三個重要的結構:M,P,S
P:表明調度的上下文,能夠把它看作一個局部的調度器,使go代碼在一個線程上跑,它是實現從N:1到N:M映射的關鍵。
圖中看,有2個物理線程M,每個M都擁有一個context(P),每個也都有一個正在運行的goroutine。
P的數量能夠經過GOMAXPROCS()來設置,它其實也就表明了真正的併發度,即有多少個goroutine能夠同時運行。
圖中灰色的那些goroutine並無運行,而是出於ready的就緒態,正在等待被調度。P維護着這個隊列(稱之爲runqueue),
Go語言裏,啓動一個goroutine很容易:go function 就行,因此每有一個go語句被執行,runqueue隊列就在其末尾加入一個
goroutine,在下一個調度點,就從runqueue中取出一個goroutine執行。
好比一個服務器,接收請求,阻塞式的方法是一個請求處理完成後,纔開始第二個請求的處理。其實在設計的時候咱們必定不會這麼作,咱們會在一開始就已經想到使用併發來處理這個場景,每一個請求啓動一個goroutine爲它服務,這樣就達到了並行的效果。這種goroutine直接按照思惟的邏輯來使用goroutine
一個場景是這樣:須要給一批用戶發送消息,正常邏輯會使用
for _, user := range users { sendMessage(user) } //可是在考慮到性能問題的時候,咱們就不會這樣作,若是users的個數很大,好比有1000萬個用戶?咱們就不必將1000萬個用戶放在一個routine中運行處理,考慮將1000萬用戶分紅1000份, //每份開一個goroutine,一個goroutine分發1萬個用戶,這樣在效率上會提高不少。這種是性能優化上對goroutine的需求
http協議實現的消息隊列,數據持久化levelDb
//httpmq mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { } //net/http包起路由作攔截處理(put,get,status,view) //接收name\data參數 //起四個channel putnamechan := make(chan string, 100) //入隊name管道 putposchan := make(chan string, 100) //入隊數據索引管道 getnamechan := make(chan string, 100) //出隊name管道 getposchan := make(chan string, 100) //出隊數據索引管道 //兩個Goroutine作消息管道流入隊出隊操做 go func(chan string, chan string) { for { name := <-putnamechan // putpos := httpmq_now_putpos(name) putposchan <- putpos } }(putnamechan, putposchan) go func(chan string, chan string) { for { name := <-getnamechan getpos := httpmq_now_getpos(name) getposchan <- getpos } }(getnamechan, getposchan) //put入隊操做 putnamechan <- name putpos := <-putposchan queue_name := name + putpos if data != "" { db.Put([]byte(queue_name), []byte(data), nil) } else if len(buf) > 0 { db.Put([]byte(queue_name), buf, nil) } //get出隊操做 getnamechan <- name getpos := <-getposchan if getpos == "0" { w.Write([]byte("HTTPMQ_GET_END")) } else { queue_name := name + getpos v, err := db.Get([]byte(queue_name), nil) if err == nil { w.Header().Set("Pos", getpos) w.Write(v) } else { w.Write([]byte("HTTPMQ_GET_ERROR")) } }
put操做
name --> putnameChannel --> 生成putPos --> putposChannel --> name+pos生成key持久化data
get操做
name --> getnameChannel --> 生成getPos --> getposChannel --> name+pos生成key getData