使用golang的channel的坑

來源:互聯網
上載者:User

很多時候我們經過使用有緩衝channel作為通訊控制的功能,以至有一些誤解和坑出現。

誤解一:有緩衝channel是順序的

執行下面代碼。

package mainimport (    "time"    "math/rand")func main(){    cache:=make(chan int,4)    go func() {        for i:=0;i< 10;i++ {            cache<-i        }    }()    go getCache(cache)    go getCache(cache)    go getCache(cache)    time.Sleep(3*time.Second)}func getCache(cache <-chan int)  {    for  {        select {        case i:=<-cache:            println(i)            time.Sleep(time.Duration(rand.Int31n(100))*time.Millisecond)        }    }}

多執行幾次看看結果,並不是每一次都是可以順序輸出的,有緩衝channel是亂序的。因為這裡讓一些同學誤解了,我在此多解釋一下。
針對通道的發送和接收操作都是可能造成相關的goroutine阻塞。試想一下,有多個goroutine向同一個channel發送資料而被阻塞,如果還channel有多餘的緩衝空間時候,最早被阻塞的goroutine會最先被喚醒。也就是說,這裡的喚醒順序與發送操作的開始順序是一致的,對接收操作而言亦為如此。無論是發送還是接收操作,運行時系統每次只會喚醒一個goroutine。 而這裡的亂序是指,如果像使用channel緩衝中多個goroutine實現順序是正確的,因為每一個goroutine搶到處理器的時間點不一致,所以不能保證順序。

誤解二:channel緩衝的大小就是並發度

如下代碼。

package mainimport ("fmt""sync""time")var wg = sync.WaitGroup{}func main() {wg.Add(2)bf := make(chan string, 64)go insert(bf)go get(bf)wg.Wait()}func insert(bf chan string) {str := "CockroachDB 的技術選型比較激進,比如依賴了 HLC 來做事務的時間戳記。但是在 Spanner 的事務模型的 Commit Wait 階段等待時間的選擇,CockroachDB 並沒有辦法做到 10ms 內的延遲;CockroachDB 的 Commit Wait 需要使用者自己指定,但是誰能拍胸脯說 NTP 的時鐘誤差在多少毫秒內?我個人認為在處理跨洲際機房時鐘同步的問題上,基本只有硬體時鐘一種辦法。HLC 是沒辦法解決的。另外 Cockroach 採用了 gossip 來同步節點資訊,當叢集變得比較大的時候,gossip 心跳會是一個非常大的開銷。當然 CockroachDB 的這些技術選擇帶來的優勢就是非常好的易用性,所有邏輯都在一個 binary 中,開箱即用,這個是非常大的優點。"for i := 0; i < 10000000; i++ {bf <- fmt.Sprintf("%s%d", str, i)}wg.Done()}func sprint(s string) {time.Sleep(1000 * time.Millisecond)}func get(bf chan string) {for {go func() {select {case str := <-bf:sprint(str)case <-time.After(3 * time.Second):wg.Done()}}()}}

很多同學乍一看以為定義了

bf := make(chan string, 64)

就是說該程式的並發度控制在了64,執行就會發現記憶體一直在增長。 因為get()函數中啟動的goroutine會越來越多,因為get()每讀取一個資料,insert()就會往channel插入一條資料,此時並發度就不是64了。 需要修改為:

package mainimport ("fmt""sync""time")var wg = sync.WaitGroup{}func main() {wg.Add(2)bf := make(chan string, 64)go insert(bf)//go get(bf)    for i:=0;i<64;i++ {        go get1(bf)    }wg.Wait()}func insert(bf chan string) {str := "CockroachDB 的技術選型比較激進,比如依賴了 HLC 來做事務的時間戳記。但是在 Spanner 的事務模型的 Commit Wait 階段等待時間的選擇,CockroachDB 並沒有辦法做到 10ms 內的延遲;CockroachDB 的 Commit Wait 需要使用者自己指定,但是誰能拍胸脯說 NTP 的時鐘誤差在多少毫秒內?我個人認為在處理跨洲際機房時鐘同步的問題上,基本只有硬體時鐘一種辦法。HLC 是沒辦法解決的。另外 Cockroach 採用了 gossip 來同步節點資訊,當叢集變得比較大的時候,gossip 心跳會是一個非常大的開銷。當然 CockroachDB 的這些技術選擇帶來的優勢就是非常好的易用性,所有邏輯都在一個 binary 中,開箱即用,這個是非常大的優點。"for i := 0; i < 10000000; i++ {bf <- fmt.Sprintf("%s%d", str, i)}wg.Done()}func sprint(s string) {time.Sleep(1000 * time.Millisecond)}func get1(bf chan string)  {    for {        select {        case str := <-bf:            sprint(str)        case <-time.After(3 * time.Second):            wg.Done()        }    }}


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.