天天看點

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P88 今日内容

go的優勢就在于并發

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P89内容回顧

go語言的日期要記住,2006-01-02 13:04:05

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

還有after和before

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

runtime.caller可以擷取到運作時的堆棧資訊

2021/9/19 老男孩帶你21周搞定Go語言 (六)

接口類型的變量底層分為兩部分:動态類和動态值。

反射的應用,可以解析json,xml各種資料解析,還有orm架構。

反射的兩個方法:reflact.Typeof得到動态類型的資訊,reflact.valueof動态值類型

2021/9/19 老男孩帶你21周搞定Go語言 (六)

把字元串解析到student的結構體

2021/9/19 老男孩帶你21周搞定Go語言 (六)

unmarshall參數是空接口,可以接收任何類型的值,然後反射去把對應字段解析

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

P90 ini配置檔案解析1

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

可以試試map類型,讀取特定字元串,值存入到相應的字段裡

2021/9/19 老男孩帶你21周搞定Go語言 (六)

讀檔案,讀出位元組類型的資料

2021/9/19 老男孩帶你21周搞定Go語言 (六)

ptr就是指針

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

傳回的是一個error類型

2021/9/19 老男孩帶你21周搞定Go語言 (六)

格式化輸出後傳回一個error類型

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

t是指針類型,elem拿到值,等于先判斷是不是指針,再判斷是不是結構體

2021/9/19 老男孩帶你21周搞定Go語言 (六)

make初始化隻針對slice,map,channel,剩下都是new,new是給值類型做初始化的。必須是要一個結構體指針,傳一個int類型的指針是不行的

2021/9/19 老男孩帶你21周搞定Go語言 (六)

換成結構體指針就沒問題了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

讀檔案,ioutil,資料儲存到一個變量,然後按照換行符切割。

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

P91 init配置解析2

配置檔案讀取出來放到了一個slice裡

2021/9/19 老男孩帶你21周搞定Go語言 (六)

一行行讀資料,遇到注釋的就跳過。如果[開頭就是段落section,把【】去掉,讀取下面的内容

2021/9/19 老男孩帶你21周搞定Go語言 (六)

提示這裡有文法錯誤

2021/9/19 老男孩帶你21周搞定Go語言 (六)

現在格式沒問題,就沒有文法錯誤了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

擷取字段名,并在相應data裡根據反射找對應的結構體,造一個結構體的嵌套,找到mysql對應的結構體,再從對應結構體裡找不同的字段

2021/9/19 老男孩帶你21周搞定Go語言 (六)

結構體名字接收變量

2021/9/19 老男孩帶你21周搞定Go語言 (六)

for循環周遊拿到資料裡的值,找到對應的mysql段落還是其他段落

2021/9/19 老男孩帶你21周搞定Go語言 (六)

使用指針

2021/9/19 老男孩帶你21周搞定Go語言 (六)

如果走到了【】段落名,那就跳出循環,讀取該段落的配置字段了,

1.也就是以等号分割這一行,等号左邊是key,右邊是value。(不規範的要去掉,提示文法錯誤)

2.根據structname去data裡面把對應的嵌套結構體給取出來。

3.周遊嵌套結構體的每一個字段,判斷tag是不是等于key。

4.如果是key=tag,給這個字段 指派

2021/9/19 老男孩帶你21周搞定Go語言 (六)

空行跳過

2021/9/19 老男孩帶你21周搞定Go語言 (六)

這樣就沒問題了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

根據struct name去data裡把對應的字段值取出來

2021/9/19 老男孩帶你21周搞定Go語言 (六)

先把key拿出來,切到等于号,key就是address,value就是後面的ip位址。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

周遊嵌套結構體字段,判斷tag是不是等于key

2021/9/19 老男孩帶你21周搞定Go語言 (六)

下面拿到的值也需要稍微改動,等于key就找到了對應的字段

2021/9/19 老男孩帶你21周搞定Go語言 (六)

第四步,指派

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

把值存起來

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

找到對應字段就退出

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

下面判斷obj,reflact如果是一個string,就設定成string

2021/9/19 老男孩帶你21周搞定Go語言 (六)

這裡字元串就都有了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

字元串有了,加個int類型,那就涉及到把之前string類型的數字轉成int類型

2021/9/19 老男孩帶你21周搞定Go語言 (六)

可以使用strconv.parseint,轉幾進制數,多少位,傳回int64和err

2021/9/19 老男孩帶你21周搞定Go語言 (六)

10進制數,64位,現在parseint還有問題

2021/9/19 老男孩帶你21周搞定Go語言 (六)

解析錯誤,17行有問題

2021/9/19 老男孩帶你21周搞定Go語言 (六)

xxx這裡應該找不到字段,就直接跳過了,沒有必要指派

2021/9/19 老男孩帶你21周搞定Go語言 (六)

port的值類型錯誤。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

現在就都加載出來了

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

判斷float

2021/9/19 老男孩帶你21周搞定Go語言 (六)

添加一個test布爾值

2021/9/19 老男孩帶你21周搞定Go語言 (六)

流程:從配置檔案讀取出,把資料依次指派到結構體裡,利用反射一個字段一個字段去找,根據結構體tag值找到key值,

2021/9/19 老男孩帶你21周搞定Go語言 (六)

所有配置檔案解析,go語言裡都是做map的

2021/9/19 老男孩帶你21周搞定Go語言 (六)

也有現成的ini庫

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P92 strconv标準庫介紹

go是強類型語言,類型和類型之間不能互相轉換,支援強制轉換的前提是支援轉換的,int64轉int32,數字和字元串類型就不能互相轉了。

數字當作ascii碼了,拿編碼找到了這個字元

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

拿到字元串的97,直接string(),是用數字做一個utf-8編碼了,去找對應符号去了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

還有一個方法,strconv.parseint,字元串轉int

2021/9/19 老男孩帶你21周搞定Go語言 (六)

這樣1000這個字元串就轉成int64了,前面的10代表10進制

2021/9/19 老男孩帶你21周搞定Go語言 (六)

10,0,傳0的話就是int類型,但傳回值定死了,就是int64

2021/9/19 老男孩帶你21周搞定Go語言 (六)

這樣就傳回int

2021/9/19 老男孩帶你21周搞定Go語言 (六)

但是轉成int一般不用上面的,Atoi就是字元串轉成int

2021/9/19 老男孩帶你21周搞定Go語言 (六)

數字轉換成字元串Itoa

2021/9/19 老男孩帶你21周搞定Go語言 (六)

strconv是把對應的字元傳解析成需要用的資料,比如boolstr

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P93 并發程式設計介紹

java做并發,需要os裡線程池,包裝一下,起一個線程,執行完再關閉,這裡os線程運作的時候會遇到上下文切換,一個線程最起碼要2M。

go裡實作了自己的線程,goroutine,切換的時候是自己切。

并發代表同一段時間 内執行多個任務。

并行代表同一時刻執行多個任務。

go的并發用goroutine實作。等于在cpu阻塞的時候去做其他的事情。類似于線程,但是是屬于使用者态的線程。

goroutine是由go語言的運作時runtime排程完成的。

channel是在用多個goroutine進行通信的,協調工作用的。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P94 建立goroutine

2021/9/19 老男孩帶你21周搞定Go語言 (六)

在調用函數的時候前面加上go 關鍵字,就能實作并發。

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

**

程式啟動之後會建立一個主goroutine去執行,go關鍵字代表開啟一個單獨的goroutine去執行hello函數(任務)**

2021/9/19 老男孩帶你21周搞定Go語言 (六)

現在列印一個main,main函數結束,由main函數啟動的goroutine也都結束了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

會停頓一下

2021/9/19 老男孩帶你21周搞定Go語言 (六)

列印多個,列印的時候順序不一定

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P95 sync.WaitGroup

改造成匿名函數,為什麼有3個999,列印i這個變量,這個變量是在外面拿的,啟動一個go routine的 時候,可能for循環轉的夠快,已經走了好幾個循環了,是以列印的時候出現了多個。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

可以在函數執行的時候把參數傳進去,這樣每個for循環就把值主動 傳進去了。說明啟動goroutine是要消耗時間和資源的。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

**優雅方式等待goroutine去結束,sync包裡有一個Waitgroup

**

2021/9/19 老男孩帶你21周搞定Go語言 (六)

goroutine對應的函數執行結束了,gocroutine才結束

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

程式編譯好了,每次執行的都一樣,指派進去了,每次執行都是一樣的

2021/9/19 老男孩帶你21周搞定Go語言 (六)

1970年到現在的納秒數,這樣肯定是不一樣的,這樣 寫的程式的随機數就沒問題

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

struct是值類型

2021/9/19 老男孩帶你21周搞定Go語言 (六)

done代表計數器結束了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

通常這麼寫,確定done了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

啟動10個goroutine

2021/9/19 老男孩帶你21周搞定Go語言 (六)

等待計數器減為0就退出,3可能還沒來得及輸出就退出了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

等待時間 長點就可以看到3了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

sync.waitgroup可以同步多個goroutine退出才退出

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P96 goroutine排程模型GMP

goroutine是使用者态的線程 ,是go語言自己實作的類似線程的東西。

goroutine和線程 的差別就是棧不一樣 。os線程一般都固定棧的記憶體是2M,一個goroutine的棧不是固定的,最小2Kb,最大1GB。

是以go語言中可以一次建立十萬作用的goroutine也是可以的。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

goroutine排程,GMP排程

G:就是goroutine,裡面除了存放本goroutine資訊外還有與所在ip的綁定等資訊。

M:machine 是Go運作時對作業系統核心線程的虛拟,M與核心線程一般是映射關系,一個gorutine最終是要放到M上執行的。

P:管理一組goroutine隊列,P裡面會存儲目前goroutine運作的上下文環境(函數指針,堆棧位址及位址邊界),P會對自己管理的goroutine隊列做一些排程(比如把占用cpu時間較長的goroutine暫停、運作後續的goroutine等等)當自己的隊列消費完了就去全局隊列裡重取,如果全局隊列裡也消費完了會去其他P的隊列裡搶任務。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

當io阻塞的時候 ,就會切換。p的個數是通過runtime.GOMAXPROCS設定,最大256,go1.5版本之後預設為實體線程數,在并發量打的時候會則更加一些P和M,但不會太多。

所有都是p排程的,也就是go語言自己排程,比其他語言用作業系統排程,就省很多資源。把m個goroutine放到一個作業系統線程上進行工作。

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

windows無效,體會不出來,先試個1核

2021/9/19 老男孩帶你21周搞定Go語言 (六)

先列印B再列印A

2021/9/19 老男孩帶你21周搞定Go語言 (六)

多核可能會出現列印錯亂的情況

2021/9/19 老男孩帶你21周搞定Go語言 (六)

預設就是cpu的核心數

2021/9/19 老男孩帶你21周搞定Go語言 (六)

作業系統啟動的是程序,但是真正幹活的是線程

2021/9/19 老男孩帶你21周搞定Go語言 (六)

作業系統線程核goroutine的關系:

1個作業系統線程對應使用者多個goroutine

go程式同時可以有多個作業系統程式設計。

goroutine核OS線程是多對多關系。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

goroutine排程模型,GMP

G是goroutine

M是用于和作業系統線程做映射的。

P是管理goroutine,阻塞的時候進行切換

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P97 channel初識

單純讓函數起一個goroutine沒有意義,肯定是中間有多個環節進行互動。

現在不是使用共享記憶體來實作資料通信(這樣會資料加鎖,并行變串行)而是通過通信,實作共享記憶體。go語言用通道實作多個goroutine通信的。

goroutine是go語言并發的執行體,channel相當于做連結。channel是一個特殊類型,類似傳送帶,遵循先入先出

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

需要指定通道中元素的類型,channel是一個引用類型,需要初始化去使用,配置設定記憶體使用。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

make,初始化slice,map,channel

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

帶緩沖區和不帶緩沖區,滿了的話有人接才能放

2021/9/19 老男孩帶你21周搞定Go語言 (六)

channel的使用有三種操作,發送,接收,關閉

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

不管發送還是接收,都是用<小于号

2021/9/19 老男孩帶你21周搞定Go語言 (六)

發送是從goroutine到channel,接收是從channel到goroutine

2021/9/19 老男孩帶你21周搞定Go語言 (六)

相當于卡在這裡了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

等于永遠放不進去,現在是一個main的一個goroutine

2021/9/19 老男孩帶你21周搞定Go語言 (六)

可以再起一個匿名函數試試

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

使用sync.waitgroup等待goroutine結束

2021/9/19 老男孩帶你21周搞定Go語言 (六)

現在就列印出來了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

下面的放進去,上面的才能取出來

2021/9/19 老男孩帶你21周搞定Go語言 (六)

沒有緩沖區的channel

2021/9/19 老男孩帶你21周搞定Go語言 (六)

帶緩沖區的channel,初始化裡,裡面最多存一個容量,是以下面就可以放進去

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

取值

2021/9/19 老男孩帶你21周搞定Go語言 (六)

隻有1個容量,是以,下面的就卡住了

2021/9/19 老男孩帶你21周搞定Go語言 (六)

關閉close掉

2021/9/19 老男孩帶你21周搞定Go語言 (六)

箭頭代表資料的流向

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

如何優雅地從通道循環取值

2021/9/19 老男孩帶你21周搞定Go語言 (六)

forange也支援從通道取值

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P98 channel練習

先造100個數放到通道1,另外的goroutine從通道1取值,每個乘平方,然後把結果放到通道2裡。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

f1循環放值,f2循環取值

2021/9/19 老男孩帶你21周搞定Go語言 (六)

最後讀不到資料,會傳回一個false,隻要不關閉,一直都是true

2021/9/19 老男孩帶你21周搞定Go語言 (六)

這個數就算出來了

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

sys.once隻執行一次

2021/9/19 老男孩帶你21周搞定Go語言 (六)

once確定某個操作隻執行一次,隻關閉一次

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

關閉通道的時候,如果原來有值,讀會繼續讀,之後傳回值是false

2021/9/19 老男孩帶你21周搞定Go語言 (六)

對一個關閉通道繼續取值,是可以取的,隻不過會是false

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

關閉的通道取多少次都是false,bool是false,字元串就是為空

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P99 單向通道

單向通道一般用在函數的參數裡,限制别人隻想發送什麼,或接收什麼。確定暴露出去的通道隻能有一項操作。限制你一個函數裡隻能往ch2裡放進去,不能取出來。

2021/9/19 老男孩帶你21周搞定Go語言 (六)

傳回的是一個通道,通道類型是時間類型。單向通道,隻能從裡面去讀取。

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

channel三種操作,接收發送,關閉。

通道狀态,nil,非空,空的,滿了,沒滿。

nil沒有初始化的時候,接收,發送都是阻塞的,關閉會panic,關閉已經關閉的會panic。

如果主程式一直運作,後面goroutine一直占記憶體,永遠不可能把記憶體釋放,這是goroutine洩露

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P100 work_pool練習

goroutine池,work_pool這種模式

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

造三個goroutine去執行任務

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

worker是包裝了一個任務,id是int,jobs是一個隻讀的通道,result是隻寫的通道。

從隻讀通道取值,算乘2 的值

2021/9/19 老男孩帶你21周搞定Go語言 (六)

起三個goroutine,5個任務

2021/9/19 老男孩帶你21周搞定Go語言 (六)

id為3的goroutine先起5個任務

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

開啟一個goroutine循環加入job

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

從job取數,計算合,發送到result

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

列印數

2021/9/19 老男孩帶你21周搞定Go語言 (六)

P101 select介紹

從多個通道去取,叫多路複用。

想要實作每次随機從c1或者c2裡取

2021/9/19 老男孩帶你21周搞定Go語言 (六)

c1取不到到c2裡取,c2取不到到c1裡取

2021/9/19 老男孩帶你21周搞定Go語言 (六)

select,多個case滿足,可以随機選一個

2021/9/19 老男孩帶你21周搞定Go語言 (六)

這樣每次執行結果都不一樣

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)

P102 作業要求

之前的日志是同步寫的,可以起一個goroutine,日志放到channel裡,一直從channel裡拿日志寫檔案。

2021/9/19 老男孩帶你21周搞定Go語言 (六)
2021/9/19 老男孩帶你21周搞定Go語言 (六)