golang 程式休眠 golang 執行緒與通道

2021-10-12 15:02:20 字數 2692 閱讀 7762

首先我們來看執行緒,在golang裡面也叫goroutine

下面我們先來看乙個例子吧

import(

"fmt"

funcmain()(i)

fmt.println("2")

上面的**就建立了乙個匿名函式,並且還傳入了乙個引數i,下面括號裡的i是實參,a是形參。

那麼上面的**能按照我們預想的列印1、2、3嗎?告訴你們吧,不能,程式只能列印出2。下面我把正確的**貼出來吧

import(

"fmt"

"time"

funcmain()(i)

fmt.println("2")

time.sleep(1 * time.second)

我只是在最後加了一行讓主線程休眠一秒的**,程式就會依

次列印出2、3、1。

那為什麼會這樣呢?因為程式會優先執行主線程,主線程執行完成後,程式會立即退出,沒有多餘的時間去執行子執行緒。如果在程式的最後讓主線程休眠1秒鐘,那程式就會有足夠的時間去執行子執行緒。

執行緒先講到這裡,下面我們來看看通道吧。

通道又叫channel,顧名思義,channel的作用就是在多執行緒之間傳遞資料的。

建立無緩衝channel

chreadandwrite :=make(chan int)

chonlyread := make(

chonlywrite := make(chan

下面我們來看乙個例子:

ch :=make(chan int)

ch go func() {

fmt.println("1")

fmt.println("2")

這段**執行時會出現乙個錯誤:fatal error: all goroutines are asleep - deadlock!

這個錯誤的意思是說執行緒陷入了死鎖,程式無法繼續往下執行。那麼造成這種錯誤的原因是什麼呢?

我們建立了乙個無緩衝的channel,然後給這個channel賦值了,程式就是在賦值完成後陷入了死鎖。因為我們的channel是無緩衝的,即同步的,賦值完成後來不及讀取channel,程式就已經阻塞了。這裡介紹乙個非常重要的概念:channel的機制是先進先出,如果你給channel賦值了,那麼必須要讀取它的值,不然就會造成阻塞,當然這個只對無緩衝的channel有效。對於有緩衝的channel,傳送方會一直阻塞直到資料被拷貝到緩衝區;如果緩衝區已滿,則傳送方只能在接收方取走資料後才能從阻塞狀態恢復。

對於上面的例子有兩種解決方案:

1、給channel增加緩衝區,然後在程式的最後讓主線程休眠一秒,**如下:

ch :=make(chan int,1)

ch go func() {

v :=

fmt.println(v)

time.sleep(1 * time.second)

fmt.println("2")

這樣的話程式就會依次列印出1、2

2、把ch

ch :=make(chan int)

go func() {

v :=

fmt.println(v)

ch fmt.println("2")

這裡就不用讓主線程休眠了,因為channel在主線程中被賦值後,主線程就會阻塞,直到channel的值在子執行緒中被取出。

最後我們看乙個生產者和消費者的例子:

import (

"fmt"

"time"

func produce(p chan

for i := 0; i < 10; i++ {

p fmt.println("send:", i)

func consumer(c

for i := 0; i < 10; i++ {

v :=

fmt.println("receive:", v)

func main() {

ch := make(chan int)

go produce(ch)

go consumer(ch)

time.sleep(1 * time.second)

在這段**中,因為channel是沒有緩衝的,所以當生產者給channel賦值後,生產者這個執行緒會阻塞,直到消費者執行緒將channel中的資料取出。消費者第一次將資料取出後,進行下一次迴圈時,消費者的執行緒也會阻塞,因為生產者還沒有將資料存入,這時程式會去執行生產者的執行緒。程式就這樣在消費者和生產者兩個執行緒間不斷切換,直到迴圈結束。

下面我們再看乙個帶緩衝的例子:

import (

"fmt"

"time"

func produce(p chan

for i := 0; i < 10; i++ {

p fmt.println("send:", i)

func consumer(c

for i := 0; i < 10; i++ {

v :=

fmt.println("receive:", v)

func main() {

ch := make(chan int, 10)

go produce(ch)

go consumer(ch)

time.sleep(1 * time.second)

在這個程式中,緩衝區可以儲存10個int型別的整數,在執行生產者執行緒的時候,執行緒就不會阻塞,一次性將10個整數存入channel,在讀取的時候,也是一次性讀取。

golang學習筆記 優雅的退出golang服務

寫了一段時間的golang後台,怎麼優雅的退出程式一直是乙個很模糊的問題。思路還是之前的思路,各種標誌和變數來回控制,雖然說是能夠滿足需求,但是總感覺那開啟的姿勢不對,下面對優雅的退出golang做乙個小總結,廢話不多說,直接上 主程式 模擬乙個服務物件,函式reload和close分別是過載和退出...

golang學習筆記 優雅的退出golang服務2

前不久介紹了如何比較 優雅的退出golang服務 雖然能夠優雅的退出,但是只是簡單的監聽了系統的訊號,後續服務模組得到資源釋放又牽扯到更多的邏輯。對於服務啟動的子協程的宣告週期顯然沒有考慮到。經過一些時間的實踐和閱讀大佬們的 對如何優雅的退出golang服務再做乙個簡單的記錄。乙個供外部呼叫的釋放資...

golang程式版本管理

版本管理主要用於對執行程式的版本追蹤,從而可以管理線上服務的執行版本,避免各個版本的服務程式混淆.這裡通常的做法為在程式中埋入版本標誌,同時該版本號會對應到git上的tag或release版本.從而對線上服務更改有乙個更全面的資訊說明.這裡將介紹基於gnu風格一種版本命名方式.1.版本號命名格式 主...