go語言開發入門

go語言開發入門

每一個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)
}

選擇 ifswitch函數

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)
                }
            }
        }
    }
}

數據(array)與切片(slice)

數組聲明: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)

Channel

  • 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) //帶緩衝

Goroutine

關鍵字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

  • M:表明真正的內核OS線程,真正幹活的人
  • G:表明一個goroutine,它有本身的棧,instruction pointer和其餘信息(正在等待的channel等等),用於調度。
  • 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執行。

其餘

  • defer語句:調用一個被 defer 的函數時在函數剛要返回以前延遲執行
  • panic/recover 異常處理語句

缺陷

  • 編譯生成的可執行文件尺寸很是大
  • 代碼可讀性差(x,y,z int, a []*struct)
  • go的濫用致使不可預見bug(注goroutine的使用應該是保守型的)

有兩種思惟邏輯會想到使用goroutine

  • 業務邏輯須要併發

好比一個服務器,接收請求,阻塞式的方法是一個請求處理完成後,纔開始第二個請求的處理。其實在設計的時候咱們必定不會這麼作,咱們會在一開始就已經想到使用併發來處理這個場景,每一個請求啓動一個goroutine爲它服務,這樣就達到了並行的效果。這種goroutine直接按照思惟的邏輯來使用goroutine

  • 性能優化須要併發

一個場景是這樣:須要給一批用戶發送消息,正常邏輯會使用

for _, user := range users {
    sendMessage(user)

}
//可是在考慮到性能問題的時候,咱們就不會這樣作,若是users的個數很大,好比有1000萬個用戶?咱們就不必將1000萬個用戶放在一個routine中運行處理,考慮將1000萬用戶分紅1000份,    //每份開一個goroutine,一個goroutine分發1萬個用戶,這樣在效率上會提高不少。這種是性能優化上對goroutine的需求

實例httpmq

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

相關文章
相關標籤/搜索