goLang學習筆記(三)

Jsp發表於2018-08-20

二十一:go協程

1、go協程是什麼
    go協程是與其他函式或方法一起併發執行的函式或方法。go協程可以看作是輕量級執行緒。與執行緒相比
    建立一個go協程的成本很小

2、go協程相比執行緒的優勢
    a:相比執行緒而言,go協程的成本極低。堆疊大小隻有若干kb,可以根據應用的需求進行增減。
        而執行緒必須指定堆疊的大小,其堆疊固定不變

    b:go協程會複用數量更少的os執行緒。即使程式有數以千計的go協程,也可能只有一個執行緒。
        如果go協程發生來阻塞,系統會再建立一個os執行緒,並把其餘go協程都移到這個新的OS執行緒

    c:go協程使用通道來進行通訊。通道用於防止多個協程訪問共享記憶體時發生競態條件,通道可以
        看作是go協程之間通訊的管道

3、啟動go協程
    呼叫函式或者方法時,在前面加上關鍵字go,可以讓一個新的go協程併發的執行

    1、啟動一個新的協程時,協程的呼叫會立即返回。與函式不同,程式控制不會去等待go協程執行完畢。
        在呼叫go協程之後,程式控制會立即返回到程式碼的下一行,忽略該協程的任何返回值

    2、如果希望執行其他的go協程,go主執行緒必須繼續執行著。如果go主協程終止,則程式終止,於是其他
        go協程不會繼續執行

    3、在go主執行緒中使用休眠,以便等待其他執行緒執行完畢,只是用於理解go協程如何工作的技巧。
        通道可用於在其他協程結束執行之前阻塞go主協程
        func main(){
            go hello()
            time.Sleep(1 * time.Second)
            fmt.Println("xsxs")
        }

4、啟動多個go協程複製程式碼

二十二:通道

通道可以想象成go協程之間通訊的管道
1、通道的宣告
    所有通道都關聯來一個型別。通道只能運輸這種型別的資料,而運輸其他型別的資料是非法的
    chan T表示T型別的通道
    定義通道: a := make(chan int)

2、通過通道進行傳送和接收
    data := <- a //讀取通道a
    a <- data //寫入通道a

3、傳送與接收預設是阻塞的
    a:當資料傳送到通道時,程式控制會在傳送資料的語句處發生阻塞,直到有其它go協程從通道讀取資料,
    才會解除阻塞
    b:當讀取通道的資料時,如果沒有其它的協程把資料寫入到通道,那麼讀取過程就會一直阻塞
    幫助go協程之間高效的通訊

4、死鎖
    a:go協程給一個通道傳送資料時,照理說會有其它go協程來接收資料,如果沒有程式就會在執行時觸
        發panic,形成死鎖
    b:同理,接收時也一樣

5、單向通道
    只能傳送或者接收資料
    a:通道轉換:把一個雙向通道轉換程唯送通道或者唯收通道

6、關閉通道和使用for range遍歷通道
    a:資料傳送方可以關閉通道,通知接收方這個通道不再有資料傳送過來
    b:從通道接收資料時,接收方可以多用一個變數來檢查通道是否已經關閉
        v, ok := <- ch複製程式碼

二十三:緩衝通道和工作池

1、緩衝通道
    a:無緩衝通道的傳送和接收過程都是阻塞的
    b:有緩衝的通道:
        一:只在緩衝已滿的情況,才會阻塞向緩衝通道傳送資料
        二:只有在緩衝為空的時候,才會阻塞從緩衝通道接收資料

    c:建立緩衝通道
        ch := make(chan type, capacity)  capacity表示容量,無緩衝通道預設是0


2、死鎖
    func main(){
        ch := make(chan string, 2)
        ch <- "nav"
        ch <- "pal"
        ch <- "ste"
        fmt.Println(<-ch)
        fmt.Println(<-ch)
    }
    向容量為2 的緩衝通道寫入3個字串,程式在第三次寫入時,由於超出來通道的容量,因此這次寫入發生
    了阻塞。
    想要這次寫操作進行下去,必須要有其他協程來讀取這個通道的資料,所有這裡發生死鎖

3、長度和容量
    a:緩衝通道的容量是指通道可以儲存的值的數量   make函式建立時指定
    b:長度是指當前排隊的元素個數

4、waitGroup
    a:waitGroup用於實現工作池,用於等待一批go協程執行結束。程式控制會一直阻塞,直到這些協程全部
    執行完畢
    b:傳遞wg的地址是很重要的。如果沒有傳遞wg的地址,那麼每個go協程將會得到一個waitGroup值的拷貝,
        因而當它們執行結束時,main函式並不會知道
        go process(i, &wg)

5、工作池的實現
    a:緩衝通道的重要作用之一就是實現工作池。工作池就是一組等待任務分配的執行緒

    b:工作池的核心功能:
        一:建立一個go協程池,監聽一個等待作業分配的輸入型緩衝通道
        二:將作業新增到該輸入型緩衝通道
        三:作業完成後,再將結果寫入一個輸出型緩衝通道
        四:從輸出型緩衝通道讀取並列印結果

    c:隨著工作協程數量的增加,完成作業的總時間會減少複製程式碼

二十四:select

1、select語句用於在多個傳送/接收通道操作中進行選擇。select語句會一直阻塞,直到傳送/接收操作準備
    就緒。
    如果有多個通道操作準備完畢,select會隨機選取其中之一執行

2、select應用

3、預設情況
    在沒有case準備就緒時,可以執行select語句中的預設情況,防止select語句一直阻塞

4、死鎖與預設情況
    func main(){
        ch := make(chan string)
        select {
        case <- ch:
        }
    }
    a:如果存在預設情況,就不會發生死鎖
    b:如果select只包含值為nil的值,也同樣會執行預設情況

5、隨機選取
    當select由多個case準備就緒時,將會隨機選取其中之一去執行
    在playground上執行不具有隨機性

6、空select
    select語句沒有任何case,會一直阻塞,導致死鎖複製程式碼

二十五:mutex

1、臨界區
    當程式併發執行時,多個go協程不應該同時訪問那些修改共享資源的程式碼

2、mutex用於提供一種加鎖機制,可確保某時刻只有一個協程在臨界區執行,防止出現競態條件
    A:mutex定義了兩個方法:Lock和Unlock。所有在Lock和Unlock之間的程式碼,都只能由一個go協程執行,
    可以避免競態條件

3、使用mutex
    傳遞mutex的地址很重要,如果傳遞的是mutex的值而非地址,那麼每個協程都會得到mutex的一份拷貝,
    競態還是會發生

4、使用通道處理競態條件

5、mutex vS 通道
    當go協程需要與其他協程通訊時,可以使用通道
    而當只允許一個協程訪問臨界區時,可以使用mutex複製程式碼

二十六:結構體取代類

go有型別和方法,支援物件導向的程式設計風格,卻沒有型別的層次結構
1、go不支援類,而是提供類結構體
    a:結構體中可以新增方法,這樣可以將資料和運算元據的方法繫結在一起,實現與類相似的效果

2、使用New()函式,而非構造器
    a:java中使用構造器來解決,一個合法的物件必須使用引數化的構造器來建立
    b:go不支援構造器,如果某型別的零值不可用,需要程式設計師來隱藏該型別,避免從其他包直接訪問
        提供一種名為NewT(parameters)的函式,按照要求來初始化T型別的變數

    c:go不支援類,但是結構體能很好的取代類,以New簽名的方法可以替代構造器複製程式碼

二十七:組合取代繼承

go不支援繼承,但它支援組合
1、通過巢狀結構體進行組合
    a:在go中,通過在結構體巢狀結構體,可以實現組合
    b:一旦一個結構體內巢狀了一個結構體欄位,go可以使我們訪問其巢狀的欄位。

2、結構體切片的巢狀
    結構頭切片不能巢狀一個匿名切片複製程式碼

二十八:多型

go通過介面實現多型,在go中隱式的實現介面。一個型別如果定義了介面所宣告的全部方法,它就實現了該介面

1、使用介面實現多型
    a:一個型別如果定義了介面的所有方法,那它就隱式的實現了該介面
    b:所有實現了介面的型別,都可以把它的值儲存在一個介面型別的變數中。使用介面的這種特性實現多型複製程式碼

二十九:defer

1、defer的用途:含有defer語句的函式,會在該函式將要返回直接,呼叫另一個函式
2、延遲方法
3、實參取值
    在go語言中,當執行defer語句的時候,就會對延遲函式的實參進行求值

4、defer棧
    當一個函式多次呼叫defer時,go會把defer呼叫放到一個棧中,按後進先出的順序執行

5、defer的實際應用
    當一個函式應該在與當前程式碼流無關的環境下呼叫時,可以使用defer複製程式碼

三十:錯誤處理

1、按照go的慣例,在處理錯誤時,通常都是將返回的錯誤與nil比較。nil表示沒有發生錯誤
2、從錯誤獲取更多資訊的不同方法
    a:斷言底層結構體型別,使用結構體欄位獲取更多資訊 PathError
    b:斷言底層結構體型別,呼叫方法獲取更多資訊   DNSError
    c:直接比較
3、不可忽略的錯誤複製程式碼


相關文章