Go學習筆記

使用go1.10版本,在liteIde里開發(fā)。

1,變量聲明后必須使用,不然編譯不過(全局變量可以不用)。

2,變量可以不用var關鍵字(簡短形式),如c := 66,但是c必須是沒有聲明過的,而且c必須在函數(shù)中

3, go1.9之后,數(shù)字類型可以不加類型關鍵字,系統(tǒng)自動推斷。

4, var(a,b = 9, 99)// 因式分解的寫法,一般用于聲明全局變量,同一行可以同時聲明多個變量,叫并行或同時賦值

5,像int, float, bool,string這些是值類型,這些類型的變量直接指向內存中的值(棧中)。當使用=賦值的時候,實際是在內存中將等號右邊的值進行了拷貝。兩邊地址不一樣。更復雜的數(shù)據(jù)類型,需要使用多個字,這些數(shù)據(jù)一般使用引用類型保存。如指針類型p1,它的值是一個地址a,指向真正的值v,p2=p1后,拷貝的只是a,指向的仍是同一個真正的值v

6,由于go函數(shù)可以多返回,有時候又不需要所有的值,(局部變量聲明不用要報錯)可以用_表示拋棄值 _,b = 5,7,5就被拋棄

7,常量const關鍵字除了用于變量不可修改,還可用于枚舉,如 const(Unknown =0, Femal = 1, Male = 2)

8,iota,特殊常量,可以認為是可以被編譯器修改的常量。每當const關鍵字出現(xiàn)時,被重置為0,在下一個const出現(xiàn)前,每出現(xiàn)一次iota,所代表的數(shù)字自動加1,const(a = iota;b = iota;c = iota ),a,b,c的值依次為0,1,2,后面兩個iota可以省略

9,<< ,>>,左移,右移雙目運算符,相當于乘以,除以2的n次方(n為移動位數(shù))。

10,select,條件判斷語句,跟switch類似,只是select會隨機運行一個case,如果沒有case,就阻塞,知道有一個case為止,select后不加判斷條件。

11,函數(shù)定義格式 fund funcName(x type, y type)(type, type){},只返回一個值的話,返回類型括號可以不要。第一個參數(shù)的type可以不要,如果兩個參數(shù)類型一致。

匿名函數(shù)命名格式區(qū)別是僅僅沒有函數(shù)名。調用不太一樣,如下調用:func(index int){xxx}(paras),paras是參數(shù)列表,沒有參數(shù)就只寫小括號。小括號表示匿名函數(shù)被調用。如:x, y := func(i, j int) (v1, v2 int) {

????????return i + 1, j + 1

????}(9, 99) // 表示直接傳入9,99兩個參數(shù)調用這個匿名函數(shù),x,y的結果分別是10,100

12,函數(shù)參數(shù)的值傳遞和引用傳遞:值傳遞=調用函數(shù)時將實際參數(shù)復制一份傳遞到函數(shù)中,這樣在函數(shù)中對參數(shù)的修改不會影響實際參數(shù);引用傳遞=調用函數(shù)時將實際參數(shù)的地址傳遞到函數(shù)中,這樣在函數(shù)中對參數(shù)的修改會陰影實際參數(shù)。

13,函數(shù)作為值:

func maxValue(x, y int) int {

????if x > y {

????????return x

????}

????return y

}

fmt.Print(maxValue(11,22)) // 輸出22

14, 函數(shù)閉包:go支持匿名函數(shù),可作為閉包。匿名函數(shù)是一個內聯(lián)語句或表達式。匿名函數(shù)的優(yōu)越性在于可以直接使用函數(shù)內的變量,不必申明。

func getSequence() func() int{

i += 0

return func() int{

i += 1

return i

}

}

nextNum := getSequence() // nextNum 是返回的一個函數(shù)

14,方法:方法就是包含接受者的函數(shù)。接受者可以是命名類型或者結構體類型的一個值或指針。所有給定類型的方法屬于該類型的方法集(感覺就是一個對象的方法)

type Circle struct{

radius float64

}

fun (c Circle) getArea() float64{

return 3.14 * c.radius * c.radius

}

fun main(){

var c1 Circle

c1.radius = 10.00

var area = c1.getArea()

}

15,數(shù)組:定義格式 var arrayName[n] type

var a = [5] float32{1,2,3,4,5}

var a1 = […] float32{1,2} // 不設置數(shù)組大小,會根據(jù)元素個數(shù)自動設置。

16,指針:變量是一個占位符,用于引用計算機內存的地址。

?指針變量定義:var varName *type ,var fp *float??罩羔樣胣il表示

指針數(shù)組=數(shù)組中每個元素指向一個值(每個元素都是一個指針), var ptr [n] *int

17,結構體定義 var structName struct{}

18,切片(slice,就是動態(tài)數(shù)組),切片不需要說明數(shù)組長度。當需要容量大且內容頻繁修改的時候,用list更好

定義格式:var s []type 或者用make()創(chuàng)建,var s []type = make([]type, len)

直接初始化: s := [] int {1,2}

其它數(shù)組的引用: s := arr[:]

根據(jù)其它數(shù)組的元素創(chuàng)建新的切片: s := arr[startIndex:endIndex], 一個不寫表示前面或后面所有的

通過一個切片創(chuàng)建一個新的切片: s? := s1[startIndex:endIndex],新片中包含startIndex表示的值,不包含endIndex包含的值。s1也可以是一個數(shù)組,slice本來也就是基于數(shù)組的一個抽象數(shù)據(jù)類型,是一個數(shù)組片段的描述。一個slice結構包括三部分,一個指向底層數(shù)組的指針ptr,一個切片的長度len,一個底層數(shù)組的長度cap。切片是可以索引的。

make創(chuàng)建: s := make([]int, len, cap) // len表示元素數(shù)據(jù)個數(shù),默認0,表示最大容量

19,追加切片append():s = append(s, 1, 2), 這里追加兩個元素,len+2,cap+4(如果新的切片大小是舊的2倍以上,cap=len,否則,len<1024,cap翻倍,大于1024,cap翻1.25倍)。如果切片作為函數(shù)參數(shù),如s是函數(shù)外參數(shù),s1是函數(shù)參數(shù)名,這個s1其實是s的一個復制。但是在函數(shù)內,s1[1] = 66這種操作是可以修改s的內容的。因為切片里是根據(jù)一個數(shù)組指針表示數(shù)組的,復制切片后指針指向的地址沒變。但是如果用append,增加的只是s1的容量,長度,s不變,所以如果打印,s看起來沒變。如果要在函數(shù)內根據(jù)append修改函數(shù)外的值,需要這樣寫:

func test(s *[]int){*s = append(*s, 22)}

20,切片拷貝copy(): copy(s,s1), 表示把s1中的數(shù)據(jù)拷貝到s中,s1中的數(shù)據(jù)順序不變,從起始位置替換s中的元素。

21,范圍(range):range可以枚舉數(shù)組,切片,unicode支付查等中的索引值和元素值

for i,c := range “go”

22,map:無序鍵值對的集合,用hash表實現(xiàn),可以迭代

定義格式:var mapName map[keyType] valueType, 可以用make創(chuàng)建,m := make(map[keyType] valueType)

如 m := make(map[string]string) m[“name”] = “xx”

range可以枚舉它 for key := range m;

還可以查看是否有一個key對應的值 value,ok := m[‘name’],? ok是bool值,表示值是否存在

23,接口:一種數(shù)據(jù)類型,它把所有具有共性的方法定義在一起,任何其它類型只要實現(xiàn)了這些方法就是實現(xiàn)了這個接口,一個應用例子如下:

type Phone interface {

? ? call()

}

type NokiaPhone struct {

}

func (nokiaPhone NokiaPhone) call() {

? ? fmt.Println("I am Nokia, I can call you!")

}

type IPhone struct {

}

func (iPhone IPhone) call() {

? ? fmt.Println("I am iPhone, I can call you!")

}

func main() {

? ? var phone Phone

? ? phone = new(NokiaPhone)

? ? phone.call(

? ? phone = new(IPhone)

? phone.call()

}

24,defer 語句會延遲函數(shù)的執(zhí)行直到上層函數(shù)返回。延遲調用的參數(shù)會立刻生成,但是在上層函數(shù)返回前函數(shù)都不會被調用。延遲的函數(shù)調用被壓入一個棧中。當函數(shù)返回時, 會按照后進先出的順序調用被延遲的函數(shù)調用。

25,go語言的并發(fā)支持

go語言相比java等一個巨大的優(yōu)勢就是可以方便的編寫并發(fā)程序。go語言內置了goroutine機制,可以快速的開發(fā)并發(fā)程序,更好的利用多核處理器資源。

go語言讓事件在新線程中執(zhí)行變得簡單,調用函數(shù)的時候前面加上 go 關鍵字就可以了。但是說到多線程,就不得不說線程之間的通信,我們很多時候要知道子線程何時結束,執(zhí)行的結果以實現(xiàn)線程的同步。go里用channel(信道)的概念。

和map一樣,信道是引用類型,用make分配內存,創(chuàng)建的時候還可以加一個可選的整型參數(shù),以限制緩存區(qū)大小。默認為0.

c := make(chan int) // 無緩存整型信道 ;c := make(chan *os,File, 100) // 緩沖的文件指針信道

可以往信道中插入數(shù)據(jù) c <- 1; 也可以從信道中讀數(shù)據(jù) <- c,

例子:

????c := make(chan int)

????go func() {

????????for i := 0; i < 10; i++ {

????????????fmt.Print("go goroutine test......", i, "\n")

????????}

????????c <- 1

????}()

????fmt.Print("waiting...\n")

????<-c

????fmt.Print("go routine over")

打印結果是:

???? waiting…?

?? ? go gorouting test…….0

……

go grouting test….9

go routine over// 如果沒有<-c,會一直阻塞。如果信道是非緩存的,則發(fā)信者在收信者接收到數(shù)據(jù)前也一直阻塞。如果信道有緩沖區(qū),發(fā)信者只有在數(shù)據(jù)被填入緩沖區(qū)前才被阻塞,如果緩沖區(qū)是滿的,意味著發(fā)信者要等到某個收信者取走一個值

限制channel的吞吐量可以用兩種方式,

1,創(chuàng)建的時候添加參數(shù)設置。 var see = make(chan int, maxNum)

2,? 通過循環(huán),把go func xxx放到循環(huán)內

信道可以像其它類型的數(shù)值一樣被分配內存并傳遞,此特性常用于實現(xiàn)安全且并行的去復用(demultiplexing)。

3,runtime.GOMAXPROCS(n)n小于cpu核數(shù),顯示的設置是否使用多核來執(zhí)行并發(fā)任務

防止主goutine過早的被運行結束的有效手段之一—同步(sync.WaitGroup)

var waitGroup sync.WaitGroup // 用于等待一組操作執(zhí)行完畢的同步工具

waitGroup.Add(3) // 改組操作的數(shù)量3.

chan1 := make(chan int64, 3) // 數(shù)字通道1

chan2 := make(chan int64, 3) // 數(shù)字通道2

chan3 := make(chan int64, 3) // 數(shù)字通道3

sync.WaitGroup代表一個類型,該類型聲明存在于代碼包sync中,類型名為WaitGroup,add(3)表示我們后面要啟用3個

groutine。

下面以一個groutine處理完成再交給第二個grouting為例:

第一個處理:

go fun(){

// 從chan1獲取處理對象

process

// 把結果傳給第二個chan2

close(chan2)// 關閉chan2

waitGroup.done()// 表示此操作完成,相當于從group中的3減去1

}

第二,三個處理一次接受上一個chan,傳給下一個。

調用的時候, 向chan1中傳遞一個一個數(shù)據(jù),完成后關閉chan1.

為了能讓這個流程執(zhí)行完成,末尾還需要加上:

waitGroup.Wait()// 等待前面那組操作(一共3個)的完成。

25,go語言并發(fā)機制

線程和進程

現(xiàn)在操作系統(tǒng)中,線程是處理調度和分配的基本單位,進程是資源分配的基本單位。每個進程由私有的虛擬空間,代碼,數(shù)據(jù)和其它各種系統(tǒng)資源組成。線程是進程內的一個執(zhí)行單元。每個進程至少有一個主線程,系統(tǒng)自動創(chuàng)建。用戶根據(jù)需要創(chuàng)建其它線程。多個線程并發(fā)地運行于同一個進程中。

并行與并發(fā)

并發(fā),一個時間段內有很多的線程或進程執(zhí)行,但在任何時間點上都只有一個在執(zhí)行,多個線程或進程爭搶時間片輪流執(zhí)行。并行,一個時間段和時間點上都有多個線程或進程在執(zhí)行。

并行需要硬件支持,單核只能并發(fā)。

并發(fā)是并行的必要條件,如果一個程序本身就不并發(fā),也就是只有一個邏輯執(zhí)行順序,那么不可能讓其并行處理。

并發(fā)不是并行的充分條件,一個并發(fā)程序,還需要多核的支持才能并行。

線程模型的3個分類

線程有用戶線程和內核級線程兩類。

第一類,多對一模型:多個用戶線程映射到一個內核線程,線程管理在用戶空間完成,此模式下,用戶線程對os透明,這種模型,好處是:線程上下文切換都發(fā)生在用戶空間,避免模態(tài)切換,對于性能有積極影響。缺點是:所有的線程基于一個內核調度實體(即內核線程),這樣只有一個處理器被利用,效率低下,并且一個線程阻塞,其它都要等待。

第二類,一對一模型:摸個用戶線程映射一個內存線程,每個線程有內核調度器獨立調度。這種模型,好處是:多核下,支持并行,效率高,一個線程阻塞,允許其它繼續(xù)執(zhí)行。缺點是:每創(chuàng)建一個用戶線程都需要創(chuàng)建一個系統(tǒng)線程對應,線程創(chuàng)建的開銷大,影響程序性能。

第三類,多對多模型:用戶線程和內核線程都有多個(部分用戶線程映射一個內核線程)。結合前兩種的優(yōu)點。這種模型需要內核線程調度器和用戶線程調度器相互操作,本質上是多個線程被綁定到了多個內核線程上,使得大部分的線程上下文切換發(fā)生在用戶空間,而多個內核線程又可以充分利用處理器資源。

groutine就采用了第三類模型。grouting機制是協(xié)程的一種實現(xiàn),golang內置調度器,可以讓多核cpu中每個cpu執(zhí)行一個協(xié)程。

調度器工作方式

整個調度,包括四個重要部分,M,G, P, sched:

sched是調度器,它維護存儲M,G的隊列和調度器的一些狀態(tài)信息

M是系統(tǒng)線程,有os管理,goroutine就是在M上運行。

P是處理器,主要用途就是來執(zhí)行grouting的,它維護一個grouting隊列,即run queue。

G是goroutine實現(xiàn)的核心結構,包含棧,指令指針等,代表一個goroutine?

單核情況下,一個M,一個P,若干個G排隊。一個G運行完自己的時間片后,讓出上下文,回到runqueue中。多核中,有多個M,每個m有一個p。

線程阻塞情況下,會在創(chuàng)建一個M1,當前的M放棄它的P,P轉到M1中去運行。

當一個p的runqueue為空,沒有G的時候,P會從另一個上下文偷取一半的G執(zhí)行。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 類型 引用類型特指slice、map、channel這三種預定義類型。 內置函數(shù)new按指定類型長度分配零值內存,...
    蕭然AND沐橦閱讀 544評論 0 0
  • 1.安裝 https://studygolang.com/dl 2.使用vscode編輯器安裝go插件 3.go語...
    go含羞草閱讀 1,690評論 0 6
  • 出處---Go編程語言 歡迎來到 Go 編程語言指南。本指南涵蓋了該語言的大部分重要特性 Go 語言的交互式簡介,...
    Tuberose閱讀 18,726評論 1 46
  • fmt格式化字符串 格式:%[旗標][寬度][.精度][arg索引]動詞旗標有以下幾種:+: 對于數(shù)值類型總是輸出...
    皮皮v閱讀 1,220評論 0 3
  • 這里,我們省略hadoop源碼導入eclipse的過程。在上一篇我們尋找main()函數(shù)的文章,我們可以看到,腳本...
    找不到工作的_Ngone閱讀 641評論 0 2

友情鏈接更多精彩內容