中文字幕一区二区人妻电影,亚洲av无码一区二区乱子伦as ,亚洲精品无码永久在线观看,亚洲成aⅴ人片久青草影院按摩,亚洲黑人巨大videos

Go 并發(fā)

Go 語(yǔ)言支持并發(fā),我們只需要通過(guò) go 關(guān)鍵字來(lái)開啟 goroutine 即可。

goroutine 是輕量級(jí)線程,goroutine 的調(diào)度是由 Golang 運(yùn)行時(shí)進(jìn)行管理的。

goroutine 語(yǔ)法格式:

go 函數(shù)名( 參數(shù)列表 )

例如:

go f(x, y, z)

開啟一個(gè)新的 goroutine:

f(x, y, z)

Go 允許使用 go 語(yǔ)句開啟一個(gè)新的運(yùn)行期線程, 即 goroutine,以一個(gè)不同的、新創(chuàng)建的 goroutine 來(lái)執(zhí)行一個(gè)函數(shù)。 同一個(gè)程序中的所有 goroutine 共享同一個(gè)地址空間。

實(shí)例

package main

import (
? ? ? ? "fmt"
? ? ? ? "time"
)

func say(s string) {
? ? ? ? for i := 0; i < 5; i++ {
? ? ? ? ? ? ? ? time.Sleep(100 * time.Millisecond)
? ? ? ? ? ? ? ? fmt.Println(s)
? ? ? ? }
}

func main() {
? ? ? ? go say("world")
? ? ? ? say("hello")
}

執(zhí)行以上代碼,你會(huì)看到輸出的 hello 和 world 是沒(méi)有固定先后順序。因?yàn)樗鼈兪莾蓚€(gè) goroutine 在執(zhí)行:

world
hello
hello
world
world
hello
hello
world
world
hello

通道(channel)

通道(channel)是用來(lái)傳遞數(shù)據(jù)的一個(gè)數(shù)據(jù)結(jié)構(gòu)。

通道可用于兩個(gè) goroutine 之間通過(guò)傳遞一個(gè)指定類型的值來(lái)同步運(yùn)行和通訊。操作符 <- 用于指定通道的方向,發(fā)送或接收。如果未指定方向,則為雙向通道。

ch <- v    // 把 v 發(fā)送到通道 ch
v := <-ch  // 從 ch 接收數(shù)據(jù)
           // 并把值賦給 v

聲明一個(gè)通道很簡(jiǎn)單,我們使用chan關(guān)鍵字即可,通道在使用前必須先創(chuàng)建:

ch := make(chan int)

注意:默認(rèn)情況下,通道是不帶緩沖區(qū)的。發(fā)送端發(fā)送數(shù)據(jù),同時(shí)必須有接收端相應(yīng)的接收數(shù)據(jù)。

以下實(shí)例通過(guò)兩個(gè) goroutine 來(lái)計(jì)算數(shù)字之和,在 goroutine 完成計(jì)算后,它會(huì)計(jì)算兩個(gè)結(jié)果的和:

實(shí)例

package main

import "fmt"

func sum(s []int, c chan int) {
? ? ? ? sum := 0
? ? ? ? for _, v := range s {
? ? ? ? ? ? ? ? sum += v
? ? ? ? }
? ? ? ? c <- sum // 把 sum 發(fā)送到通道 c
}

func main() {
? ? ? ? s := []int{7, 2, 8, -9, 4, 0}

? ? ? ? c := make(chan int)
? ? ? ? go sum(s[:len(s)/2], c)
? ? ? ? go sum(s[len(s)/2:], c)
? ? ? ? x, y := <-c, <-c // 從通道 c 中接收

? ? ? ? fmt.Println(x, y, x+y)
}

輸出結(jié)果為:

-5 17 12

通道緩沖區(qū)

通道可以設(shè)置緩沖區(qū),通過(guò) make 的第二個(gè)參數(shù)指定緩沖區(qū)大?。?/p>

ch := make(chan int, 100)

帶緩沖區(qū)的通道允許發(fā)送端的數(shù)據(jù)發(fā)送和接收端的數(shù)據(jù)獲取處于異步狀態(tài),就是說(shuō)發(fā)送端發(fā)送的數(shù)據(jù)可以放在緩沖區(qū)里面,可以等待接收端去獲取數(shù)據(jù),而不是立刻需要接收端去獲取數(shù)據(jù)。

不過(guò)由于緩沖區(qū)的大小是有限的,所以還是必須有接收端來(lái)接收數(shù)據(jù)的,否則緩沖區(qū)一滿,數(shù)據(jù)發(fā)送端就無(wú)法再發(fā)送數(shù)據(jù)了。

注意:如果通道不帶緩沖,發(fā)送方會(huì)阻塞直到接收方從通道中接收了值。如果通道帶緩沖,發(fā)送方則會(huì)阻塞直到發(fā)送的值被拷貝到緩沖區(qū)內(nèi);如果緩沖區(qū)已滿,則意味著需要等待直到某個(gè)接收方獲取到一個(gè)值。接收方在有值可以接收之前會(huì)一直阻塞。

實(shí)例

package main

import "fmt"

func main() {
? ? // 這里我們定義了一個(gè)可以存儲(chǔ)整數(shù)類型的帶緩沖通道
? ? ? ? // 緩沖區(qū)大小為2
? ? ? ? ch := make(chan int, 2)

? ? ? ? // 因?yàn)?ch 是帶緩沖的通道,我們可以同時(shí)發(fā)送兩個(gè)數(shù)據(jù)
? ? ? ? // 而不用立刻需要去同步讀取數(shù)據(jù)
? ? ? ? ch <- 1
? ? ? ? ch <- 2

? ? ? ? // 獲取這兩個(gè)數(shù)據(jù)
? ? ? ? fmt.Println(<-ch)
? ? ? ? fmt.Println(<-ch)
}

執(zhí)行輸出結(jié)果為:

1
2

Go 遍歷通道與關(guān)閉通道

Go 通過(guò) range 關(guān)鍵字來(lái)實(shí)現(xiàn)遍歷讀取到的數(shù)據(jù),類似于與數(shù)組或切片。格式如下:

v, ok := <-ch

如果通道接收不到數(shù)據(jù)后 ok 就為 false,這時(shí)通道就可以使用 close() 函數(shù)來(lái)關(guān)閉。

實(shí)例

package main

import (
? ? ? ? "fmt"
)

func fibonacci(n int, c chan int) {
? ? ? ? x, y := 0, 1
? ? ? ? for i := 0; i < n; i++ {
? ? ? ? ? ? ? ? c <- x
? ? ? ? ? ? ? ? x, y = y, x+y
? ? ? ? }
? ? ? ? close(c)
}

func main() {
? ? ? ? c := make(chan int, 10)
? ? ? ? go fibonacci(cap(c), c)
? ? ? ? // range 函數(shù)遍歷每個(gè)從通道接收到的數(shù)據(jù),因?yàn)?c 在發(fā)送完 10 個(gè)
? ? ? ? // 數(shù)據(jù)之后就關(guān)閉了通道,所以這里我們 range 函數(shù)在接收到 10 個(gè)數(shù)據(jù)
? ? ? ? // 之后就結(jié)束了。如果上面的 c 通道不關(guān)閉,那么 range 函數(shù)就不
? ? ? ? // 會(huì)結(jié)束,從而在接收第 11 個(gè)數(shù)據(jù)的時(shí)候就阻塞了。
? ? ? ? for i := range c {
? ? ? ? ? ? ? ? fmt.Println(i)
? ? ? ? }
}

執(zhí)行輸出結(jié)果為:

0
1
1
2
3
5
8
13
21
34