Golang Channel 高併發的初始

deliangyang發表於2018-06-22

go中channel是一種重要的引用資料型別,可以看作是管道,可以通過併發的核心單元傳送或者接收資料進行通訊。

操作符 <-,箭頭指向,即資料的流向,沒有指明方向,那麼Channel就是雙向的,既可以接收資料,也可以傳送資料

ch <- v         // 傳送值到Channel ch中
v := <-ch       // 從Channel ch中接收資料,並賦值給v

// 初始化 Channel ch, 類似於Slice,map的資料型別一樣,channel必須先建立,然後再使用

ch := make(chan  int)
複製程式碼

Channel的方向

  • 不確定雙向性、指定唯一單向
chan T          // 既可以接收資料,也可以傳送資料
chan<- float64  // 只可以用來傳送 float64 型別的資料
<-chan int      // 只可以接收 float64 資料型別的資料
複製程式碼
  • <-總是優先和最左邊的型別結合
chan<- chan int    // 等價 chan<- (chan int)
chan<- <-chan int  // 等價 chan<- (<-chan int)
<-chan <-chan int  // 等價 <-chan (<-chan int)
chan (<-chan int)
複製程式碼

設定Channel的容量,代表Channel快取的大小

make初始化的時候可以設定 如果沒有設定Channel的大小,或者設定為0,那麼預設Channel的沒有快取的,當接收者和傳送者都準備好了後,他們通訊才會發生阻塞(blocking) 如果我們設定了快取的大小,那麼就有可能不會傳送阻塞了,只有buffer滿了後,傳送者才會阻塞,只有清空了快取,接收者才會阻塞。 一個nil的Channel不會通訊。

make(chan int, 100)
複製程式碼

關閉Channel

內建的方法close()可以關閉Channel,如何檢測Channel是否被關閉

defer close(c)          // 關閉 channel

v, ok := <-ch           // 檢測 channel是否被關閉
複製程式碼

select的使用,類似於switch

case用可能處理的接收語句,有可能是傳送語句,還有可能是預設 default

timeout 超時處理

如果沒有case需要處理,select語句就會一直阻塞著

import "time"
import "fmt"
func main() {
    c1 := make(chan string, 1)
    go func() {
        time.Sleep(time.Second * 2)
        c1 <- "result 1"
    }()
    
    select {
        case res := <-c1:
            fmt.Println(res)
        case <-time.After(time.Second * 1):
            fmt.Println("timeout 1")
    }
}
複製程式碼

其實使用time.After函式,它是返回一個<-chan Time的單向channel,在指定時間傳送一個當前時間給返回的channel中

同步

channel可以用在goroutine之間的同步

import (
	"fmt"
	"time"
)
func worker(done chan bool) {
	time.Sleep(time.Second)
	// 通知任務已完成
	done <- true
}
func main() {
	done := make(chan bool, 1)
	go worker(done)
	// 等待任務完成
	<-done
}
複製程式碼

生產者和消費者


package main

import (
	"fmt"
	"time"
)

func main() {

	fmt.Println("show channel")
	queue := make(chan int, 1)
	go test.Producer(queue)
	go test.Consumer(queue)
	time.Sleep(1e9)
}

func Producer(queue chan<- int)  {
	for i := 0; i < 10; i++ {
		fmt.Println("send:", i)
		queue<- i+10000
	}
}

func Consumer(queue <-chan int) {
	for i := 0; i < 10; i++ {
		v := <-queue
		fmt.Println("receive:", v)
	}
}

複製程式碼

相關文章