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

Go 并發(fā)

Go 語言支持并發(fā),我們只需要通過 go 關鍵字來開啟 goroutine 即可。

goroutine 是輕量級線程,goroutine 的調(diào)度是由 Golang 運行時進行管理的。

goroutine 語法格式:

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

例如:

go f(x, y, z)

開啟一個新的 goroutine:

f(x, y, z)

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

實例

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í)行以上代碼,你會看到輸出的 hello 和 world 是沒有固定先后順序。因為它們是兩個 goroutine 在執(zhí)行:

world
hello
hello
world
world
hello
hello
world
world
hello

通道(channel)

通道(channel)是用來傳遞數(shù)據(jù)的一個數(shù)據(jù)結構。

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

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

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

ch := make(chan int)

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

以下實例通過兩個 goroutine 來計算數(shù)字之和,在 goroutine 完成計算后,它會計算兩個結果的和:

實例

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)
}

輸出結果為:

-5 17 12

通道緩沖區(qū)

通道可以設置緩沖區(qū),通過 make 的第二個參數(shù)指定緩沖區(qū)大小:

ch := make(chan int, 100)

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

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

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

實例

package main

import "fmt"

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

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

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

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

1
2

Go 遍歷通道與關閉通道

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

v, ok := <-ch

如果通道接收不到數(shù)據(jù)后 ok 就為 false,這時通道就可以使用 close() 函數(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ù)遍歷每個從通道接收到的數(shù)據(jù),因為 c 在發(fā)送完 10 個
? ? ? ? // 數(shù)據(jù)之后就關閉了通道,所以這里我們 range 函數(shù)在接收到 10 個數(shù)據(jù)
? ? ? ? // 之后就結束了。如果上面的 c 通道不關閉,那么 range 函數(shù)就不
? ? ? ? // 會結束,從而在接收第 11 個數(shù)據(jù)的時候就阻塞了。
? ? ? ? for i := range c {
? ? ? ? ? ? ? ? fmt.Println(i)
? ? ? ? }
}

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

0
1
1
2
3
5
8
13
21
34