go語言學習 goroutine

2022-11-24 18:02:55 字數 3325 閱讀 9316

o 語言有一個很重要的特性就是 goroutine, 我們可以使用 goroutine 結合 channel 來開發併發程式。

併發程式指的是可以同時執行多個任務的程式,這裡的同時執行並不一定指的是同一時刻執行,在單核cpu的機器下,在同一時刻只可能有一個任務在執行,但是由於cpu的速度很快,在不斷的切換著多個任務,讓它們交替的執行,因此巨集觀上看起來就像是同時在執行; 而在多核的機器上,併發程式中的多個任務是可以實現在同一時刻執行多個的,此時併發的多個任務是在並行執行的。

goroutine 是 go 語言中的併發執行單元,我們可以將多個任務分別放在多個 goroutine 中,來實現併發程式。下面先看一個例子:

package main

import "fmt"

func hello()

func main()

上述程式的執行結果如下:

bye!!!

hello world!!!

上面這個例子展示了使用 goroutine 的幾個要點:

程式啟動時,我們的主函式 main 也是在一個單獨的 goroutine 中執行的。

go hello()就是用於建立一個 goroutine, 即 go 關鍵字加上 要在 goroutine 中執行的函式(也可以是匿名函式,不過必須是呼叫的形式)

最後兩句是用於將 main 函式阻塞在這裡,直到我們按下回車鍵,之所以這麼做是因為,我們不知道新建立的 goroutine 和 main goroutine 的執行順序,有可能主程式先執行完成,此時主程式結束,我們就看不到新 goroutine 的執行效果了。(通常不會使用這種方法)

以上就是 goroutine 的基本用法

前面我們學習了怎樣建立並行的執行單元,但是每個執行單元之間是完全獨立的,如果我們想在執行期間交換資料,即進行通訊,此時就得依靠另一個概念 - channels, 即通道,這個名字十分貼切,就像在不同的併發執行單元之間連線了一根管道,然後通過這跟管道來傳送和接收資料。

goroutine 和 channel 經常結合在一起使用,下面學習一些 channel 的用法:

建立 channel

ch1 := make(chan int)
channel 也需要使用 make 函式來建立,也就是說 channel 也是一種引用型別(make函式會返回低層資料結構的引用給channel)

向 channel 中讀寫資料

前面說了 channel 是用於 goroutine 之間通訊的, 自然能夠從 channel 中寫入和讀取資料,使用的都是<-操作符

ch := make(chan int)

ch<- 1 // 向 channel 中寫入資料

var a int = <-ch // 從 channel 中讀取資料

關閉 channel

在我們使用完一個 channel 之後,可以呼叫 close() 方法來關閉一個 channel, 關閉之後的通道,不能夠再進行資料的寫操作, 但是仍然可以讀取之前寫入成功的資料(如果沒有資料了,將返回零值)。

channel 的基本操作就是上面這麼多,不過實際上,channel 是有兩種的: 無緩衝的 和 有緩衝的。上面我們建立的是無快取的,有快取的建立方式是ch := make(chan int, 2), 二者的區別是:

無緩衝的 channel 的傳送操作將導致傳送者的 goroutine 阻塞,直到在另一個 goroutine 上對其進行接收操作。如果先發生的是接收操作,那麼接收者將被阻塞,直到在另一個 goroutine 上對其進行傳送操作。

帶快取的 channel 可以快取多個資料,因此不會立即阻塞,只有當快取滿了之後,傳送者才可能會被阻塞,並且只有到快取為空時,接收者才可能被阻塞

例1: 通道用於傳遞訊息

package main

import "fmt"

func main() ()

msg := <- message // 從 channel 讀取資料

fmt.println(msg)

}

例2: 利用通道進行同步

package main

import "fmt"

func hello()

func main()

當使用 channel 作為引數,我們可以指定 channel 為單向的,即讓通道在函式中只能傳送,或者只能接收資料,以此來提高程式的安全性.

語法:例子:

package main

import "fmt"

// 這裡的 message 在函式 send 中就是一個只能傳送資料的通道

func send(msg string, message chan<- string)

// 這裡的 message 在函式 receive 中就是一個只能傳送資料的通道

func receive(message <-chan string) string

func main()

輸出結果是hello, 此時在函式 send 中,message 通道就只能用於傳送資料,而在函式 receive 中通道只能接收資料,通過引數的限制使其在函式內部成為了單向的通道。

go語言提供了一個 select 關鍵字,可以使用它來等待多個通道的操作,以實現多路複用。語法:

select
其中的每個 case 表示一個 channel 的操作,當case語句後面指定通道的操作可以執行時,select 才會執行 case 之後的語句。此時其他的語句都不會被執行。

例子: 超時處理

package main

import "time"

import "fmt"

func main() ()

select

ch2 := make(chan string, 1)

go func() ()

select

}

上面的例子中我們定義了兩個通道和兩個select結構,是為了進行對比,第一個channel會在等待兩秒之後被寫入資料,而在 select 中,第二個case語句只會等待一秒,然後就會執行,因此就會執行超時操作。而在第二個 select 中,第二個 case 語句會等待三秒。所以上述程式的結果如下:

timeout 1

result 2

go Goroutine洩露

洩露情況分類 go協程單純地陷入死迴圈中。傳送不接收 向沒有接收者的channel傳送資訊。我們知道,傳送者一般都會配有相應的接收者。理想情況下,我們希望接收者總能接收完所有傳送的資料,這樣就不會有任何問題。但現實是,一旦接收者發生異常退出,停止繼續接收上游資料,傳送者就會被阻塞。package m...

Go語言學習 goroutine

goroutine 是 golang 中在語言級別實現的輕量級執行緒,僅僅利用 go 就能立刻起一個新執行緒。多執行緒會引入執行緒之間的同步問題,在 golang 中可以使用 channel 作為同步的工具。通過 channel 可以實現兩個 goroutine 之間的通訊。建立一個 channel...

Go開發 八 goroutine和channel

程序是程式在作業系統中的一次執行過程,系統進行資源分配和排程的一個獨立單位。執行緒是程序的一個執行實體,是cpu排程和分派的基本單位,它是比程序更小的能獨立執行的基本單位。一個程序可以建立和撤銷多個執行緒 同一個程序中的多個執行緒之間可以併發執行.多執行緒程式在一個核的cpu上執行,就是併發 多執行...