Channel - cruisechang/wiki-golang GitHub Wiki

Initial

//初始化一個具有5個buffer的channel。
c:=make(chan int,5)

//初始化沒有buffer的channel
c:=make(chan int)

Attribute

  • Channel是值類型(是指Channel本身,不是Channel裡面的元素)

  • Channel的功能是傳遞元素,不是儲存元素。

  • Channel裡的元素是有先後順序的。先進先出(FIFO)。

  • Channel裡的元素具有原子性。

  • Channel裡的元素只能被read一次,不會有兩個Goroutine read到相同元素。

  • 元素一但被read,立刻就從channel中刪除。

  • Channel的buffer數量是固定的,一但初始化之後就不能更改。

Operation

  • Channel的操作本身是同步的。

  • 不同Goroutine可以對同一個channel進行send,receive操作。

Send/Receive

c:=make(chan int,5)
//Send to c
c<-1

//Receive from c
x:=<-c

//或是接收第二個值,判斷receive是否成功。
//當channel被關閉時,ok=false,此時就可知道receive是失敗的,即便還是有取到資料。
//此時取到的資料不是正確的,是資料類型的0值。
x,ok:=<-c 

ch:=make(chan int,3)
ch<-1
ch<-2
x:=<-ch	
fmt.Println(x) //x=1
close(ch)
x,ok:=<-ch
fmt.Println(x,ok) //x=2,ok=true
x,ok=<-ch
fmt.Println(x,ok) //x=0 (int type zero value),ok=false

對no buffer channel 進行操作

如下範例,此時當前Goroutine會被block住,

直到有其他Goroutine對c這個channel進行read操作。

因為channel本身是個通道,並不是容器,且這個channel並未設定buffer,

所以不容許存放資料在channel裡,必須即時取走,所以在未被取走前,會block後續執行。

//No buffer chan
c:=make(chan int)
c<-1

Close Channel

    ch:=make(chan int,5)
    close(ch)

    //對已經close channel 發送,產生panic
    ch<-1

    //再次close,產生panic
    close(ch)
  • 應在發送端進行close(),不應在接收端進行close()。避免發送端產生panic。
  • 對已close的channel(或未初始化的channel)進行發送,會產生panic。
  • close之後,接收端依舊可以接收channel裡剩餘的元素。
  • close之後,接收端如果有用ok來判斷接收正確否,並不會立刻得到false,而是在接收完所有元素才會得到false。

傳址給channel/傳實體給channel的差異

  • 傳址給channel,途中改變元素的值,後來取到的值 ->會改變

  • 傳實體給channel,途中改變元素的值,後來取到的值 ->不會改變

func main() {
    type Sct struct{
       ID string
    }

    //傳址
    s := &Sct{ID: "id"}
    c := make(chan *Sct, 5)
    oriID := s.ID
    c <- s
    s.ID = "new id"
    rs := <-c
    newID := rs.ID
    fmt.Printf("傳址進入channel 途中改變變數值,初始後來不同 oriID: %s, newID :%s \n", oriID, newID)
        
    //傳實體
    s2 := Sct{ID: "id"}
    c2 := make(chan Sct, 5)
    oriID = s2.ID
    c2 <- s2
    s2.ID = "new id"
    rs2 := <-c2
    newID = rs2.ID
    fmt.Printf("傳實體進入channel 途中改變變數值,初始與後會相同 oriID: %s, newID :%s \n", oriID, newID)

}