第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開(kāi)發(fā)者教程

Go 入門教程

Go 語(yǔ)言基礎(chǔ)教程
01 Go語(yǔ)言簡(jiǎn)介 02 Go 在 Windows 上的安裝及配置 03 Go 在 Linux 上的安裝與配置 04 Go 在 MacOS 上的安裝及配置 05 Git 的下載和安裝 06 VSCode 編輯器安裝和配置 07 Go 的變量聲明 08 Go 的變量賦值 09 Go 語(yǔ)言的 := 10 Go 的整型(int) 11 Go 的無(wú)符號(hào)整型(uint) 12 Go 的浮點(diǎn)型(float) 13 Go 的字符類型 14 Go 的布爾型(bool) 15 Go 的強(qiáng)制類型轉(zhuǎn)換 16 Go 語(yǔ)言的常量 17 Go 語(yǔ)言中代替枚舉的辦法 18 Go 語(yǔ)言中的運(yùn)算符 19 Go 語(yǔ)言的分支語(yǔ)句 20 Go 語(yǔ)言的循環(huán)語(yǔ)句 21 Go 語(yǔ)言的通道 22 Go 語(yǔ)言中的函數(shù) 23 Go 語(yǔ)言函數(shù)中的 defer 24 Go 語(yǔ)言中的閉包 25 Go 語(yǔ)言的指針 26 Go 語(yǔ)言中的數(shù)組 27 Go 語(yǔ)言中的切片 28 Go 語(yǔ)言中的 Map 29 Go 語(yǔ)言中的 range 30 Go 語(yǔ)言拓展以有類型 31 Go 語(yǔ)言中的結(jié)構(gòu)體和"面向?qū)ο?quot; 32 Go 語(yǔ)言中的接口 33 Go 語(yǔ)言類型的內(nèi)嵌 34 Go 語(yǔ)言中的 nil 35 Go 語(yǔ)言函數(shù)式編程 36 Go 語(yǔ)言中的錯(cuò)誤和異常處理 37 Go 語(yǔ)言的并發(fā) 38 Go 語(yǔ)言中的包 39 Go 語(yǔ)言 go mod 包依賴管理工具 40 Go 語(yǔ)言的文件操作 41 Go 語(yǔ)言中的系統(tǒng)包 42 Go 語(yǔ)言的 strings 系統(tǒng)包的使用 43 Go 語(yǔ)言中的變參 44 Go 語(yǔ)言中的反射 45 Go 語(yǔ)言性能測(cè)試 46 使用 Go 語(yǔ)言搭建簡(jiǎn)易登錄功能 47 使用 gin 包優(yōu)化登錄功能

Go 語(yǔ)言中的多線程操作是其語(yǔ)言的一大特色,它具有其它語(yǔ)言無(wú)法比擬的,可以近乎無(wú)限開(kāi)啟的線程。在 Go 語(yǔ)言中被稱之為 goroutine ,它是線程的輕量級(jí)實(shí)現(xiàn)。Go 語(yǔ)言的并發(fā)廣泛的應(yīng)用在服務(wù)器性能調(diào)優(yōu)的場(chǎng)景中,這也是越來(lái)越多的游戲服務(wù)器開(kāi)發(fā)都在往 Go 語(yǔ)言傾斜的原因之一。

1.Go 語(yǔ)言的 goroutine

在 Go 語(yǔ)言中使用 go 關(guān)鍵字來(lái)創(chuàng)建 goroutine ,形如go 函數(shù)名()的形式去創(chuàng)建。每一個(gè) goroutine 必須是一個(gè)函數(shù),這個(gè)函數(shù)也可以是匿名函數(shù)

代碼示例:

package main

import (
    "fmt"
    "time"
)

func main() {
    //打印0到10的數(shù)字
    go print0to10()
    //打印A到Z的字符
    go func() {
        for i := 'A'; i <= 'K'; i++ {
            fmt.Println("printAtoK:", string(i))
            time.Sleep(time.Microsecond)
        }
    }()
    time.Sleep(time.Second)
}

func print0to10() {
    for i := 0; i <= 10; i++ {
        fmt.Println("print0to10:", i)
        time.Sleep(time.Microsecond)
    }
}
  • 第 10 行:創(chuàng)建一個(gè)打印0到10數(shù)字的函數(shù)的 goroutine;
  • 第 11 行:使用匿名函數(shù)的方式創(chuàng)建一個(gè)打印A到Z的字符的 goroutine;
  • 第 15 和第 24 行:運(yùn)行等待,讓出執(zhí)行資源給其它 goroutine;
  • 第 18 行:main 函數(shù)也是一個(gè) goroutine,在它執(zhí)行結(jié)束后系統(tǒng)會(huì)殺掉在這個(gè) goroutine 中執(zhí)行的所有g(shù)oroutine ,所以要在 main 函數(shù)中加一個(gè)等待,為其內(nèi)部的 goroutine 留出執(zhí)行時(shí)間。

執(zhí)行結(jié)果:

圖片描述

從執(zhí)行結(jié)果中可以看出打印數(shù)字和打印字符的兩個(gè) goroutine 是并發(fā)執(zhí)行的。執(zhí)行順序是由 cpu 來(lái)調(diào)度的,所以執(zhí)行結(jié)果可能每次都不一樣。

2. Go語(yǔ)言并發(fā)通訊

其它語(yǔ)言并發(fā)時(shí)進(jìn)程中的通訊一般都是通過(guò)共享內(nèi)存(全局變量)的方式來(lái)實(shí)現(xiàn)的,這樣一來(lái)各個(gè)模塊之間的耦合會(huì)變得非常緊密。所以后來(lái)提出了使用通訊來(lái)共享內(nèi)存這一概念,來(lái)解耦合。在 Go 語(yǔ)言中就是使用 channel 的方式來(lái)達(dá)到這一目的的。

代碼示例:

package main

import (
    "fmt"
    "time"
)

var c1 chan rune = make(chan rune, 0)
var c2 chan int = make(chan int, 0)

func main() {
    //打印0到10的數(shù)字
    go print0to10()
    //打印A到Z的字符
    go func() {
        c2 <- 0
        for i := 1; i <= 11; i++ {
            char := <-c1
            fmt.Println("printAtoK:", string(char))
            c2 <- i
        }
    }()
    time.Sleep(time.Second)
}

func print0to10() {
    for i := 'A'; i <= 'K'; i++ {
        num := <-c2
        fmt.Println("print0to10:", num)
        c1 <- i
    }
}

上述代碼主要實(shí)現(xiàn)的功能為,使用兩個(gè)通道來(lái)使兩個(gè) goroutine 互相通訊,從而使得它們的打印安裝輪流打印的方式打印數(shù)字和字母。

  • 第 8 行:實(shí)例化一個(gè)字符通道用于接收字符;
  • 第 9 行:實(shí)例化一個(gè)數(shù)字通道用于接收數(shù)字;
  • 第 16 行:向數(shù)字通道中塞入數(shù)字0,用于觸發(fā)打印數(shù)字的 goroutine;
  • 第 18 行:從字符通道中獲取一個(gè)待打印的字符。若通道中無(wú)字符,則阻塞等待;
  • 第 20 行:字符打印完畢之后再向數(shù)字通道中塞入后續(xù)數(shù)字,觸發(fā)打印數(shù)字的 goroutine;
  • 第 28 行:從數(shù)字通道中獲取待打印的數(shù)字,若通道中無(wú)數(shù)字,則阻塞等待;
  • 第 30 行:數(shù)字打印完畢之后再向字符通道中塞入后續(xù)字符,觸發(fā)打印字符的 goroutine。

執(zhí)行結(jié)果:

圖片描述

和沒(méi)用使用 channel 之前的代碼不同,這次等同于使用 channel 實(shí)現(xiàn)了 goroutine 的調(diào)度,使其輪流執(zhí)行。

3. Go語(yǔ)言進(jìn)程鎖

在之前介紹 map 的小節(jié)中提到過(guò)線程不安全的 map 。之所以線程不安全是因?yàn)槠鋬?nèi)部實(shí)現(xiàn)機(jī)制中無(wú)法同時(shí)讀寫(xiě),若有兩個(gè) goroutine 一個(gè)在讀取 map 中的值,而另一個(gè)在更新 map 中的值,就會(huì)導(dǎo)致程序崩潰。

代碼示例:

package main

import (
    "fmt"
    "time"
)

func main() {
    m := map[string]int{"A": 1, "B": 2, "C": 3, "D": 1, "E": 2, "F": 3}
    //創(chuàng)建100個(gè)goroutine對(duì)map進(jìn)行讀寫(xiě)
    for i := 0; i < 100; i++ {
        go func() {
            for v := range m {
                m[v] = 100
            }
        }()
    }
    time.Sleep(time.Second)
    fmt.Println(m)
}

執(zhí)行上述代碼有時(shí)會(huì)輸出正確結(jié)果:

圖片描述

但更多的時(shí)候會(huì)輸出讀寫(xiě)沖突的錯(cuò)誤:

圖片描述

這個(gè)就是線程不安全的 map 不建議使用的原因,除了直接使用線程安全的 map 之外,還可以為這些 goruntine 加上鎖,使其無(wú)法同時(shí)對(duì) map 進(jìn)行讀寫(xiě)操作,這樣也可以保障各線程的安全。

代碼示例:

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var lock sync.Mutex//定義一個(gè)鎖變量
    m := map[string]int{"A": 1, "B": 2, "C": 3, "D": 1, "E": 2, "F": 3}
    for i := 0; i < 100; i++ {
        go func() {
            lock.Lock()//在讀取map前鎖定這個(gè)鎖,使其它線程訪問(wèn)這個(gè)鎖要阻塞
            for v := range m {
                m[v] = 100
            }
            lock.Unlock()//在讀取map前釋放這個(gè)鎖
        }()
    }
    time.Sleep(time.Second)
    fmt.Println(m)
}

加了鎖之后,你就會(huì)發(fā)現(xiàn)無(wú)論執(zhí)行幾次,執(zhí)行結(jié)果都是正確的。

圖片描述

4. 小結(jié)

本文主要介紹了Go語(yǔ)言中的多線程——goroutine。其實(shí)現(xiàn)是線程的輕量實(shí)現(xiàn),所以可以無(wú)限制的開(kāi)啟。在使用過(guò)程中需要注意:

  • goroutine 執(zhí)行無(wú)先后順序,由 cpu 統(tǒng)一調(diào)度。
  • goroutine 之間內(nèi)存的共享通過(guò)使用 channel 來(lái)通訊實(shí)現(xiàn)。
  • goroutine 使用線程不安全的變量類型時(shí)可以用鎖將其鎖定。