溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Golang通道Chan是什么

發(fā)布時(shí)間:2020-11-10 10:30:07 來源:億速云 閱讀:177 作者:小新 欄目:編程語言

這篇文章給大家分享的是有關(guān)Golang通道Chan是什么的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考。一起跟隨小編過來看看吧。

首先我們來看線程,在golang里面也叫g(shù)oroutine

在讀這篇文章之前,我們需要了解一下并發(fā)與并行。golang的線程是一種并發(fā)機(jī)制,而不是并行。它們之間的區(qū)別大家可以上網(wǎng)搜一下,網(wǎng)上有很多的介紹。

下面我們先來看一個(gè)例子吧

import(
         "fmt"
)

funcmain(){

    go fmt.Println("1")
    fmt.Println("2")    
}

在golang里面,使用go這個(gè)關(guān)鍵字,后面再跟上一個(gè)函數(shù)就可以創(chuàng)建一個(gè)線程。后面的這個(gè)函數(shù)可以是已經(jīng)寫好的函數(shù),也可以是一個(gè)匿名函數(shù)

funcmain(){    var i=3    go func(a int) {        fmt.Println(a)
        fmt.Println("1")
    }(i)
    fmt.Println("2")}

上面的代碼就創(chuàng)建了一個(gè)匿名函數(shù),并且還傳入了一個(gè)參數(shù)i,下面括號(hào)里的i是實(shí)參,a是形參。

那么上面的代碼能按照我們預(yù)想的打印1、2、3嗎?告訴你們吧,不能,程序只能打印出2。下面我把正確的代碼貼出來吧

import(    "fmt"
    "time"    )funcmain(){    var i = 3    go func(a int) {        fmt.Println(a)
        fmt.Println("1")
    }(i)
    fmt.Println("2")
    time.Sleep(1 * time.Second)}

我只是在最后加了一行讓主線程休眠一秒的代碼,程序就會(huì)依

次打印出2、3、1。
那為什么會(huì)這樣呢?因?yàn)槌绦驎?huì)優(yōu)先執(zhí)行主線程,主線程執(zhí)行完成后,程序會(huì)立即退出,沒有多余的時(shí)間去執(zhí)行子線程。如果在程序的最后讓主線程休眠1秒鐘,那程序就會(huì)有足夠的時(shí)間去執(zhí)行子線程。

線程先講到這里,下面我們來看看通道吧。

通道又叫channel,顧名思義,channel的作用就是在多線程之間傳遞數(shù)據(jù)的。

創(chuàng)建無緩沖channel

chreadandwrite :=make(chan int)

chonlyread := make(<-chan int) //創(chuàng)建只讀channel
chonlywrite := make(chan<- int) //創(chuàng)建只寫channel
下面我們來看一個(gè)例子:

    ch :=make(chan int)     
    ch <- 1
      go func() {
        <-ch
        fmt.Println("1")
      }()
      fmt.Println("2")

這段代碼執(zhí)行時(shí)會(huì)出現(xiàn)一個(gè)錯(cuò)誤:fatal error: all goroutines are asleep - deadlock!

這個(gè)錯(cuò)誤的意思是說線程陷入了死鎖,程序無法繼續(xù)往下執(zhí)行。那么造成這種錯(cuò)誤的原因是什么呢?

我們創(chuàng)建了一個(gè)無緩沖的channel,然后給這個(gè)channel賦值了,程序就是在賦值完成后陷入了死鎖。因?yàn)槲覀兊腸hannel是無緩沖的,即同步的,賦值完成后來不及讀取channel,程序就已經(jīng)阻塞了。這里介紹一個(gè)非常重要的概念:channel的機(jī)制是先進(jìn)先出,如果你給channel賦值了,那么必須要讀取它的值,不然就會(huì)造成阻塞,當(dāng)然這個(gè)只對(duì)無緩沖的channel有效。對(duì)于有緩沖的channel,發(fā)送方會(huì)一直阻塞直到數(shù)據(jù)被拷貝到緩沖區(qū);如果緩沖區(qū)已滿,則發(fā)送方只能在接收方取走數(shù)據(jù)后才能從阻塞狀態(tài)恢復(fù)。

對(duì)于上面的例子有兩種解決方案:

1、給channel增加緩沖區(qū),然后在程序的最后讓主線程休眠一秒,代碼如下:

    ch :=make(chan int,1)
    ch <- 1
    go func() {
        v := <-ch
        fmt.Println(v)
    }()
    time.Sleep(1 * time.Second)
    fmt.Println("2")

這樣的話程序就會(huì)依次打印出1、2

2、把ch<-1這一行代碼放到子線程代碼的后面,代碼如下:

    ch :=make(chan int)    go func() {
        v := <-ch
        fmt.Println(v)
    }()
    ch <- 1
    fmt.Println("2")

這里就不用讓主線程休眠了,因?yàn)閏hannel在主線程中被賦值后,主線程就會(huì)阻塞,直到channel的值在子線程中被取出。

最后我們看一個(gè)生產(chǎn)者和消費(fèi)者的例子:

import (    "fmt"
    "time")func produce(p chan<- int) {    for i := 0; i < 10; i++ {
        p <- i
        fmt.Println("send:", i)
    }
}func consumer(c <-chan int) {    for i := 0; i < 10; i++ {
        v := <-c
        fmt.Println("receive:", v)
    }
}func main() {
    ch := make(chan int)    go produce(ch)    go consumer(ch)
    time.Sleep(1 * time.Second)
}

在這段代碼中,因?yàn)閏hannel是沒有緩沖的,所以當(dāng)生產(chǎn)者給channel賦值后,生產(chǎn)者這個(gè)線程會(huì)阻塞,直到消費(fèi)者線程將channel中的數(shù)據(jù)取出。消費(fèi)者第一次將數(shù)據(jù)取出后,進(jìn)行下一次循環(huán)時(shí),消費(fèi)者的線程也會(huì)阻塞,因?yàn)樯a(chǎn)者還沒有將數(shù)據(jù)存入,這時(shí)程序會(huì)去執(zhí)行生產(chǎn)者的線程。程序就這樣在消費(fèi)者和生產(chǎn)者兩個(gè)線程間不斷切換,直到循環(huán)結(jié)束。

下面我們再看一個(gè)帶緩沖的例子:

import (    "fmt"
    "time")func produce(p chan<- int) {    for i := 0; i < 10; i++ {
        p <- i
        fmt.Println("send:", i)
    }
}func consumer(c <-chan int) {    for i := 0; i < 10; i++ {
        v := <-c
        fmt.Println("receive:", v)
    }
}func main() {
    ch := make(chan int, 10)    go produce(ch)    go consumer(ch)
    time.Sleep(1 * time.Second)
}

在這個(gè)程序中,緩沖區(qū)可以存儲(chǔ)10個(gè)int類型的整數(shù),在執(zhí)行生產(chǎn)者線程的時(shí)候,線程就不會(huì)阻塞,一次性將10個(gè)整數(shù)存入channel,在讀取的時(shí)候,也是一次性讀取。

感謝各位的閱讀!關(guān)于Golang通道Chan是什么就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI