首先我們來看執行緒,在golang裡面也叫goroutine
下面我們先來看乙個例子吧
import
( "fmt"
)funcmain
()
在golang裡面,使用go這個關鍵字,後面再跟上乙個函式就可以建立乙個執行緒。後面的這個函式可以是已經寫好的函式,也可以是乙個匿名函式
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(<-chan int) //建立唯讀channel
chonlywrite := make(chan<- int) //建立只寫channel
下面我們來看乙個例子:
ch :=make(chan
int)
ch <-1
gofunc() ()
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 <-1
gofunc() ()
time.sleep(1 * time.second)
fmt.println("2")
這樣的話程式就會依次列印出1、2
2、把ch<-1這一行**放到子執行緒**的後面,**如下:
ch :=make(chan
int)
gofunc() ()
ch <-1
fmt.println("2")
這裡就不用讓主線程休眠了,因為channel在主線程中被賦值後,主線程就會阻塞,直到channel的值在子執行緒中被取出。
最後我們看乙個生產者和消費者的例子:
import (
"fmt"
"time"
)func produce(p chan
<- int)
}func consumer(c <-chan
int)
}func main()
在這段**中,因為channel是沒有緩衝的,所以當生產者給channel賦值後,生產者這個執行緒會阻塞,直到消費者執行緒將channel中的資料取出。消費者第一次將資料取出後,進行下一次迴圈時,消費者的執行緒也會阻塞,因為生產者還沒有將資料存入,這時程式會去執行生產者的執行緒。程式就這樣在消費者和生產者兩個執行緒間不斷切換,直到迴圈結束。
下面我們再看乙個帶緩衝的例子:
import (
"fmt"
"time"
)func produce(p chan
<- int)
}func consumer(c <-chan
int)
}func main()
在這個程式中,緩衝區可以儲存10個int型別的整數,在執行生產者執行緒的時候,執行緒就不會阻塞,一次性將10個整數存入channel,在讀取的時候,也是一次性讀取。
另外,可以參考:
Golang 關於通道 Chan 詳解
首先我們來看執行緒,在golang裡面也叫goroutine 在讀這篇文章之前,我們需要了解一下併發與並行。golang的執行緒是一種併發機制,而不是並行。它們之間的區別大家可以上網搜一下,網上有很多的介紹。下面我們先來看乙個例子吧 import fmt funcmain 在golang裡面,使用g...
golang的chan有趣用法
寫這個部落格的背景是我面試一家公司,這家公司的cto給我出了一道我認為挺有意思的題,題的大概是這樣的 抽象乙個柵欄 type barrier inte ce 建立柵欄物件 func newbarrier n int barrier 柵欄的實現類 type barrier struct 測試 func...
golang中chan型別的位址
chan型別本是就是指標,因此直接列印即可,不需要再取位址.如果在取位址就是 指向指標的指標 pointer to pointer 即類似c c 中的二級指標 如 int a int p a int pp p 其中pp就是二級指標 package main import fmt func main ...